स्टोरेज मैनेजमेंट

ज़्यादातर Java डेवलपर का सवाल यह होता है कि J2ObjC से मेमोरी मैनेजमेंट कैसे लागू किया जाता है, क्योंकि Java में गारबेज कलेक्शन है और ऑब्जेक्ट-C में डिफ़ॉल्ट रूप से ऐसा नहीं होता. iOS में मेमोरी मैनेजमेंट के दो तरीके होते हैं: पहचान फ़ाइलों की गिनती और अपने-आप पहचान फ़ाइलों की गिनती (ARC) करने की सुविधा.

J2ObjC चुने गए तरीके के आधार पर अलग-अलग मेमोरी मैनेजमेंट कोड जनरेट करता है. ARC का इस्तेमाल करने वाला कोड जनरेट करने के लिए, -use-arc विकल्प की मदद से अनुवाद करें. डिफ़ॉल्ट रूप से, यह मैन्युअल तौर पर रेफ़रंस गिनती का इस्तेमाल करता है.

पहचान फ़ाइलों की गिनती

रेफ़रंस की गिनती करने का तरीका, ऑब्जेक्ट के मालिकाना हक को साफ़ तौर पर दिखाता है. एक तरीके में कोई ऑब्जेक्ट बनाते समय उसका मालिकाना हक तब तक मौजूद रहता है, जब तक कि वह उस ऑब्जेक्ट को रिलीज़ न कर दे. जब किसी दूसरे तरीके से ऑब्जेक्ट लिया जाता है, तो डेटा पाने का तरीका, ऑब्जेक्ट को बनाए रखता है. ऐसा तब किया जाता है, जब तरीके से डेटा मिलने के बाद ऑब्जेक्ट का रेफ़रंस देने की ज़रूरत होती है. जब किसी तरीके को किसी ऑब्जेक्ट का रेफ़रंस देने की ज़रूरत नहीं हो, तो इसे रिलीज़ करना ज़रूरी होता है. जब किसी ऑब्जेक्ट की बनाए रखने की संख्या शून्य होती है, तो उसकी मेमोरी फ़्री हो जाती है और ऑब्जेक्ट मान्य नहीं रहता. जब ऑब्जेक्ट फ़्री किए जाते हैं, तो उनकेDealloc() तरीके को उनके इंस्टेंस वैरिएबल का मालिकाना हक छोड़ने के लिए कहा जाता है.

इस तकनीक में एक समस्या यह है कि किसी ऑब्जेक्ट का मालिकाना हक कैसे ट्रांसफ़र किया जाए. उदाहरण के लिए, कोई ऑब्जेक्ट बनाने के लिए फैक्ट्री तरीके को कॉल किया जा सकता है. अगर फ़ैक्ट्री तरीका, वापस करने से पहले ऑब्जेक्ट को छोड़ देता है (क्योंकि अब वह ऑब्जेक्ट का मालिक नहीं होना चाहता है), तो कॉल करने का तरीका उसे बनाए रखने से पहले वह ऑब्जेक्ट फ़्री हो जाता है.

किसी ऑब्जेक्ट का मालिकाना हक ट्रांसफ़र करने के लिए, कोई तरीका इसे अपने-आप रिलीज़ होने वाला मैसेज (रिलीज़ मैसेज की जगह) भेजता है. यह रिलीज़ मैसेज को हटा देता है. इससे फ़ैक्ट्री बनाने वाले तरीके को, वापस करने के लिए कोई ऑब्जेक्ट बनाने में मदद मिलती है. साथ ही, ऑब्जेक्ट को अमान्य किए बिना, उसका मालिकाना हक वापस लिया जा सकता है. नियमित अंतरालों पर (जैसे, किसी iOS ऐप्लिकेशन में हर इवेंट लूप के इटरेशन के बाद), ऑटो-रिलीज़ पूल "खाली" होता है. इसका मतलब है कि उस पूल के सभी ऑब्जेक्ट को, डिफ़र्ड रिलीज़ के मैसेज भेजे जाते हैं. जिन ऑब्जेक्ट की गिनती शून्य तक कम हो जाती है उन्हें सामान्य तरीके से फ़्री कर दिया जाता है.

मेमोरी मैनेजमेंट का बोझ डेवलपर पर होता है, इसलिए रेफ़रंस गिनती के तरीके से मेमोरी को लीक करना आसान है. हालांकि, Apple इस समस्या को कम करने के लिए, कुछ सबसे सही तरीके सुझाव देता है, जिन्हें J2ObjC लागू करता है.

मेमोरी लीक का पता लगाने के लिए, रनटाइम और टूल सहायता भी मौजूद है. ऐप्लिकेशन के बंद होने पर, ऑब्जेक्टिव-सी रनटाइम, पता लगाए गए सभी लीक की रिपोर्ट करता है. इसी वजह से J2ObjC, J2ObjC टेस्ट को एक्ज़ीक्यूटेबल बाइनरी में बदल देता है. Xcode में Clang इस्तेमाल किया जाता है. साथ ही, इस कंपाइलर में मेमोरी से जुड़ी समस्याओं का बेहतरीन स्टैटिक विश्लेषण होता है, जिसे Xcode अपने Analyze कमांड की मदद से उपलब्ध कराता है.

अपने-आप पहचान फ़ाइलों की गिनती (एआरसी) करने की सुविधा

मेमोरी मैनेज करने के लिए Apple, ARC तरीका इस्तेमाल करने का सुझाव देता है. यह, रेफ़रंस की गिनती की ज़िम्मेदारी कंपाइलर पर डाल देता है. इससे कंपाइलर के दौरान उसे बनाए रखने, रिलीज़ करने, और अपने-आप रिलीज़ होने के सही तरीके जुड़ जाते हैं. ARC, iOS 5 और इसके बाद के वर्शन पर चलने वाले डिवाइसों के लिए कमज़ोर रेफ़रंस का इस्तेमाल करता है.

हमारा सुझाव है कि प्रोजेक्ट, अनुवाद किए गए कोड के लिए ARC का इस्तेमाल करें. ट्रांसपाइल किया गया ऑब्जेक्ट-सी कोड, हाथ से लिखे गए ऑब्जेक्टिव-सी कोड की तरह ही है. ARC का इस्तेमाल करने से डेवलपर को मेमोरी से जुड़ी सामान्य गड़बड़ियों से बचने में मदद मिल सकती है. जैसे, ज़्यादा रिलीज़ करना या कम रेफ़रंस देना, जिससे मेमोरी मैनेजमेंट आसान हो जाता है और गड़बड़ियों की संभावना कम हो जाती है.

ध्यान दें कि डिफ़ॉल्ट रूप से ARC, अपवाद के तौर पर सुरक्षित नहीं है. खास तौर पर, अपवाद इस्तेमाल किए जाने पर, इससे मेमोरी लीक होती है. जावा में अपवाद होना काफ़ी आम है और आम तौर पर इसे वापस पाया जा सकता है. इसलिए, यह समस्याजनक हो सकती है. आर्क के साथ कंपाइल करते समय -fobjc-arc-exceptions का इस्तेमाल करने से, उचित परफ़ॉर्मेंस लागत के साथ लीक ठीक हो जाएंगे.

हमारा सुझाव है कि नए प्रोजेक्ट, हाथ से लिखे हुए ऑब्जेक्टिव सी कोड के लिए ARC का इस्तेमाल करें. साथ ही, मैन्युअल तौर पर रेफ़रंस के तौर पर गिनती तभी करें, जब प्रोफ़ाइल बनाने वाले डेटा से, असली परफ़ॉर्मेंस की समस्या दिखे. ARC और गैर-ARC कोड, दोनों को बिना किसी समस्या के एक ही ऐप्लिकेशन में कंपाइल करके लिंक किया जा सकता है.

कमज़ोर रेफ़रंस

फ़ील्ड को com.google.devtools.j2objc.Weak की मदद से एनोटेट किया जा सकता है. ट्रांसपाइलर इस फ़ील्ड का इस्तेमाल ऐसे फ़ील्ड जनरेट करने के लिए करता है जो Objective-C के कमज़ोर रेफ़रंस सिमैंटिक का पालन करते हैं. रेफ़रंस के तौर पर गिनती का इस्तेमाल करते समय, इसका मतलब है कि जब फ़ील्ड को शुरू किया जाता है, तो यह उस पर लागू नहीं होता है. साथ ही, इंस्टेंस रिलीज़ होने पर यह अपने-आप रिलीज़ हो जाता है. ARC के साथ, कमज़ोर फ़ील्ड को __unsafe_unretained एनोटेशन के साथ मार्क किया जाता है और उससे जुड़ी प्रॉपर्टी को कमज़ोर बताया जाता है.

कुछ मामलों में, इनर क्लास इंस्टेंस अपने बाहरी इंस्टेंस के साथ रेफ़रंस साइकल में आता है. यहां com.google.devtools.j2objc.WeakOuter की जानकारी का इस्तेमाल, अंदरूनी क्लास को मार्क करने के लिए किया जाता है. इसलिए, आउटर क्लास के रेफ़रंस को ऊपर बताए गए तरीके से ही माना जाता है. इस जानकारी का असर अंदरूनी क्लास के दूसरे फ़ील्ड पर नहीं पड़ता है.

J2ObjC, WeakReference क्लास के साथ भी काम करता है. इसलिए, इसका इस्तेमाल करने वाला Java कोड, अनुवाद करने के दौरान उसी तरह काम करेगा. ध्यान रखें कि WeakReference, JVM पर स्वाभाविक रूप से तय नहीं है; ऐसे ऐप्लिकेशन जो अनुमान को बनाए रखते हुए, मेमोरी लीक से बचना चाहते हैं, उन्हें @Weak और @WeakOuter को प्राथमिकता देनी चाहिए.

मेमोरी प्रबंधन टूल