14

मैं विचार बनाते समय संदर्भ/गतिविधि मेमोरी लीक को रोकने के लिए सर्वोत्तम प्रथाओं पर अध्ययन कर रहा हूं, और मुझे यह निश्चित जानकारी नहीं मिल रही है कि क्या है या इसकी अनुमति नहीं है कक्षाओं में स्थिर क्षेत्रों के लिए आता है।एंड्रॉइड: स्टेटिक फ़ील्ड्स और मेमोरी लीक्स

public class MyOuterClass extends Activity{ 
    private MyInnerClass; 
    MyInnerClass = (MyInnerClass) findViewById(<XML call here>); 
    MyInnerClass.myXInt = 3; 

    // onCreate(), onResume(), etc. 

    public static class MyInnerClass extends SurfaceView implements Runnable{ 
     // Safe variables? 
     private static int myXInt, myYInt; 
     private static boolean myBoolean; 
     // Potentially safe? 
     private static Canvas myCanvas; 
     // Definitely bad. 
     private static Context myContext; 

     public MyInnerClass(Context context){ 
     myContext = context;  // This is bad. 
     } 
    } 
} 

मैं थोड़ा क्या JVM वास्तव में MyInnerClass के लिए classloader मानता है पर उलझन में हूँ:

चलो कहते हैं कि मैं इस फॉर्म की एक कोड करते हैं। तकनीकी रूप से, चूंकि यह एक SurfaceView ऑब्जेक्ट है, ऐसा लगता है कि एप्लिकेशन ने MyInnerClass को एक बार तुरंत चालू करने के बाद स्थिर चर हमेशा मौजूद होना चाहिए (जो तब होता है जब दृश्य पहली बार फुलाया जाता है), और फिर तब तक वहां रहें जब तक कि एप्लिकेशन स्वयं समाप्त नहीं हो जाता। यदि ऐसा है, तो बिटमैप्स और कैनवास ऑब्जेक्ट्स को भी खुले रहने और ढेर को भरने से क्या रोकता है?

एकमात्र कथन जो मैंने कभी बार-बार देखा है, यह है कि आप स्थिर संदर्भ को रिसाव नहीं कर सकते जैसे कि मैंने कन्स्ट्रक्टर में दिखाया है, लेकिन यह उससे परे कभी नहीं जाता है। क्या यह वास्तव में एकमात्र चीज है जिसे आप नहीं कर सकते?

+0

आपके 'कैनवास' आदि को 'स्थिर 'होने की आवश्यकता नहीं है। इस तरह यह वास्तव में हमेशा के लिए ढेर में रहेंगे – zapl

+1

यदि ऐसा है तो क्या स्थिरता (यानी - निजी स्थैतिक अंतिम int MY_CONSTANT) को रोकता है, जो किसी भी वर्ग को गतिविधि (और इसके संदर्भ) को खोलता है? – SeaNick

उत्तर

27

जावा/एंड्रॉइड में static चर या स्थिर कचरा नहीं होगा। कक्षा में लोड होने के बाद यह कक्षा में लोड होने के बाद बस वहां रहता है। क्लास लोडर हमेशा आपके ऐप के अंदर सभी कक्षाओं के लिए समान होता है और जिसकी आपके सभी वर्गों के लिए स्थिर संदर्भ होते हैं (उदाहरण के लिए MyInnerClass.class)। चूंकि क्लास लोडर नहीं जाता है, इसलिए आपकी कक्षाएं ऐसा नहीं करतीं क्योंकि इन्हें संदर्भित किया जाता है क्योंकि & इसलिए कचरा संग्रह योग्य नहीं है।

अपने उदाहरण

public class SomeClass extends SurfaceView { 
    private static Context myContext; 

    public MyInnerClass(Context context){ 
    myContext = context;  // This is bad. 
    } 
} 

कि वास्तव में बुरा है की तरह

। भले ही SomeClass का कोई संदर्भ मौजूद न हो (उदाहरण के लिए Activity जो दिखाता है कि आपका कस्टम SurfaceView समाप्त हो गया है) Context (और static वैरिएबल/स्थिर SomeClass में स्थिर/निरंतर स्थिर रहेंगे। आप उन सभी को लीक कर सकते हैं क्योंकि यह संभव नहीं है कचरा इकट्ठा करने के लिए Context इत्यादि। यदि आपके पास एक नियमित चर संदर्भ है तो एक बार जब उस चर के उदाहरण में उस संदर्भ में कोई और संदर्भ नहीं है, तो पूरे उदाहरण में इसके अन्य संदर्भों के संदर्भ शामिल हैं और कचरा इकट्ठा किया जा सकता है। जावा परिपत्र को भी संभाल सकता है संदर्भ ठीक है।

स्थिरांक के लिए आप ऐसा करना चाहते हैं और यह आमतौर पर खराब नहीं होता है क्योंकि यह स्थिरांक की मात्रा और उनकी स्मृति की मात्रा बड़ी नहीं होती है। इसके अलावा स्थिरांक नहीं (चाहिए नहीं) अन्य उदाहरणों का संदर्भ लें जो Context या Bitmap जैसी बड़ी मात्रा में मेमोरी लेते हैं।

स्थैतिक चर के माध्यम से मेमोरी लीक बनाने की संभावना के अलावा आप भी समस्याएं पैदा कर सकते हैं यदि आप एक ही समय में सभी उदाहरणों के लिए केवल एक ही चीज़ नहीं चाहते हैं। उदाहरण के लिए यदि आप अपने SurfaceView के Bitmap को static चर में सहेजते हैं तो आपके पास दो अलग-अलग छवियां नहीं हो सकती हैं। भले ही दो SurfaceView एस एक ही समय में प्रदर्शित नहीं होते हैं, आप समस्याओं में भाग ले सकते हैं क्योंकि प्रत्येक नया उदाहरण शायद पुरानी छवि को ओवरराइट कर देगा और यदि आप अन्य SurfaceView पर वापस जाते हैं तो आप अप्रत्याशित रूप से गलत छवि दिखाते हैं। मुझे यकीन है कि आप यहां static का उपयोग नहीं करना चाहते हैं।

तथ्य यह है कि आपकी आंतरिक कक्षा static class का मतलब यह नहीं है कि आपको स्थिर चर का उपयोग करना है - इसका मतलब यह है कि यह static विधि की तरह व्यवहार करता है क्योंकि यह आवृत्ति चर का उपयोग नहीं कर सकता है (वे जो नहीं हैं static) आपकी कक्षा में।

मेमोरी लीक से बचने के लिए आपको बस स्थिर चर का उपयोग नहीं करना चाहिए। जब तक आप विशेष सामान नहीं करते हैं (उदाहरण के लिए कक्षा के उदाहरणों की गिनती) तब तक उनका उपयोग करने की आवश्यकता नहीं है। Constants ठीक हैं।

+0

धन्यवाद। मुझे लगता है कि सांख्यिकी की इच्छा रखने के लिए समग्र तर्क इसलिए था क्योंकि अवधारणात्मक रूप से, अधिकांश दृश्य वस्तुओं को केवल एक उदाहरण की आवश्यकता होती है, क्योंकि वे आमतौर पर स्क्रीन पर एक विशिष्ट स्क्रीन या ऑब्जेक्ट का प्रतिनिधित्व करते हैं। यह उन्हें स्थिर बनाने के लिए बहुत अधिक कुशल कोड-वार लगता है, लेकिन मैं वहां की कमी को समझता हूं। जीसी की कुल दया पर चर छोड़ने के बारे में मुझे परेशान करने वाली एकमात्र चीज यह है कि जब मुझे स्मृति को मुक्त करने की आवश्यकता होगी, और मेरे ऐप में जो कुछ भी मैंने देखा है, उससे मेरा कोई नियंत्रण नहीं है, यह हमेशा बिटमैप ऑपरेशन के दौरान होता है, जो मुझे डर लगता है वह झटकेदार फ्रेम दर में बदल जाएगा। – SeaNick

+1

आपको इसे जीवित रखने और इसे पुन: उपयोग करने के लिए कुछ स्थिर होने की आवश्यकता नहीं है। यह तब तक अस्तित्व में रहेगा जब तक आपके पास इसका संदर्भ न हो। और स्थिरता का उपयोग आमतौर पर अधिक स्मृति खपत का कारण बनता है यदि आप अपने सभी स्थिर संदर्भों को उचित रूप से 'शून्य' करना भूल जाते हैं। + उदाहरण देखें उदाहरण के लिए स्क्रीन को घुमाएं उदाहरण के लिए – zapl

+1

मैं स्क्रीन अभिविन्यास को बंद रखता हूं, लेकिन यह एक बहुत अच्छा बिंदु है। एक बार फिर धन्यवाद! – SeaNick

संबंधित मुद्दे