2009-08-25 23 views
29

किसी वस्तु को कचरा एकत्र करने से कैसे रोकें?ऑब्जेक्ट को कचरा इकट्ठा करने से कैसे रोकें?

क्या अंतिम रूप देने या प्रेत संदर्भ या किसी अन्य दृष्टिकोण से कोई दृष्टिकोण है?

मुझे इस प्रश्न को एक साक्षात्कार में पूछा गया था। साक्षात्कारकर्ता ने सुझाव दिया कि finalize() का उपयोग किया जा सकता है।

+0

कुछ कोड प्रदान करें टुकड़े –

+0

राहुल, आप निर्देशन कर रहे थे विशेष रूप से किसी को भी की ओर "कुछ कोड के टुकड़े प्रदान करें", या थे आप अपने प्रश्न की आवश्यकताओं को अद्यतन करना चाहते हैं? –

+0

अरे मैंने अपने ques –

उत्तर

32

एक संदर्भ रखें। यदि आपका ऑब्जेक्ट समय-समय पर एकत्र हो रहा है, तो यह एक लक्षण है कि आपके आवेदन के डिज़ाइन में आपके पास एक बग है।

कचरा कलेक्टर केवल उन वस्तुओं को एकत्र करता है जिनके लिए आपके आवेदन में कोई संदर्भ नहीं है। यदि कोई वस्तु नहीं है जो स्वाभाविक रूप से संग्रहित वस्तु का संदर्भ देगी, तो खुद से पूछें कि इसे जीवित क्यों रखा जाना चाहिए।

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

public class Singleton { 
    private static Singleton uniqueInstance; 

    private Singleton() { 
    } 

    public static synchronized Singleton getInstance() { 
    if (uniqueInstance == null) { 
     uniqueInstance = new Singleton(); 
    } 
    return uniqInstance; 
    } 
} 

संपादित करें: तकनीकी तौर पर, आप अपने finalizer में कहीं एक संदर्भ स्टोर कर सकते हैं। यह ऑब्जेक्ट को तब तक एकत्रित करने से रोक देगा जब तक संग्राहक फिर से निर्धारित नहीं करता कि कोई और संदर्भ नहीं है। फाइनलर को केवल एक बार में बुलाया जाएगा, हालांकि, आपको यह सुनिश्चित करना होगा कि आपके ऑब्जेक्ट (इसके सुपरक्लास सहित) को पहले संग्रह के बाद अंतिम रूप देने की आवश्यकता नहीं है। हालांकि, मैं आपको सलाह दूंगा कि इस तकनीक का वास्तविक कार्यक्रमों में उपयोग न करें। (ऐसा लगता है कि मुझे WTF चिल्ला !? सहयोगियों छोड़ देंगे;)

protected void finalize() throws Throwable { 
    MyObjectStore.getInstance().store(this); 
    super.finalize(); // questionable, but you should ensure calling it somewhere. 
    } 
+0

क्या विधि –

+2

को अंतिम रूप देने में किया जा सकता है क्या आप अन्य ऑब्जेक्ट्स को अपने ऑब्जेक्ट के लिए एक नया संदर्भ संग्रहीत करने के लिए उत्तेजित कर सकते हैं। नोट, हालांकि, किसी भी दिए गए ऑब्जेक्ट के लिए सबसे अधिक बार इसे अंतिम रूप दिया जाता है, इसलिए जब संग्राहक निर्धारित करता है कि इसे फिर से एकत्र किया जा सकता है तो इसे फिर से अंतिम रूप नहीं दिया जाएगा। – Tobias

+0

"(यह मेरे जैसे सहकर्मियों को डब्ल्यूटीएफ चिल्लाएगा !?)" हां मैंने कहा लेकिन यह एक साक्षात्कारकर्ता ने मुझसे पूछा था, इसलिए मुझे कोई विचार नहीं है कि उसने मुझसे यह सवाल क्यों पूछा :) –

3

अगर अभी वस्तु के लिए एक संदर्भ है, यह कचरा एकत्र नहीं किया जाएगा। यदि इसके कोई संदर्भ नहीं हैं, तो आपको परवाह नहीं करनी चाहिए।

दूसरे शब्दों में - कचरा कलेक्टर केवल कचरा इकट्ठा करता है। इसे अपना काम करने दो।

+0

अन्य में, दूसरे शब्दों - कलेक्टर –

0

मेरा मानना ​​है कि इसके लिए वहां एक पैटर्न है। यकीन नहीं है कि यह कारखाना पैटर्न है। लेकिन आपके पास एक वस्तु है जो आपकी सभी वस्तुओं को बनाती है और उनका संदर्भ रखती है। जब आप उनके साथ समाप्त हो जाते हैं, तो आप उन्हें स्पष्ट रूप से कॉल करने के लिए कारखाने में संदर्भित करते हैं।

2

मुझे संदेह है कि आप क्या कह रहे हैं यदि आपकी finalize विधि अंतिम रूप से ऑब्जेक्ट के संदर्भ को दूर करती है। इस मामले में (यदि Java Language Spec का मेरा पठन सही है) finalize विधि फिर से नहीं चली जाएगी, लेकिन ऑब्जेक्ट अभी तक कचरा एकत्र नहीं किया जाएगा।

यह वास्तविक जीवन में किसी चीज की तरह नहीं है, संभवतः दुर्घटना से!

2

यह उन साक्षात्कार-केवल-समय में से एक जैसा लगता है-आप इसे देखेंगे। अंतिम रूप() चलाया जाता है जब आपकी ऑब्जेक्ट कचरा एकत्र हो रही है, इसलिए संग्रह को रोकने के लिए वहां कुछ डालने के लिए यह बहुत विपरीत होगा। आम तौर पर आप केवल एक संदर्भ धारण करते हैं और आपको बस इतना ही चाहिए।

मुझे यह भी यकीन नहीं है कि क्या होगा यदि आप फाइनल में कुछ के लिए एक नया संदर्भ तैयार करेंगे - चूंकि कचरा कलेक्टर पहले से ही इसे इकट्ठा करने का फैसला कर चुका है, तो क्या आप एक शून्य रेफरी के साथ खत्म हो जाएंगे? किसी भी मामले में, एक गरीब विचार की तरह लगता है। जैसे

public class Foo { 
    static Foo reference; 
    ... 
    finalize(){ 
    reference = this; 
    } 
} 

मुझे शक है इस काम करेगा, या यह काम करते हैं लेकिन जीसी implenetation पर निर्भर हो सकता है, या "अनिर्दिष्ट व्यवहार" हो। बुरा लगता है, यद्यपि।

9

आपके साक्षात्कारकर्ता की तलाश का चाल शायद यह है कि वह आपको यह जानना चाहता है कि आप कचरा संग्रहण को स्मृति रिसाव को मजबूर कर किसी ऑब्जेक्ट को हटाने से रोक सकते हैं।

जाहिर है, यदि आप कुछ लंबे समय तक संदर्भ में वस्तु का संदर्भ रखते हैं, तो इसे एकत्र नहीं किया जाएगा, लेकिन ओपी के भर्तीकर्ता ने यही नहीं पूछा। यह कुछ ऐसा नहीं है जो अंतिम रूप में होता है।

आप को अंतिम रूप देने विधि के भीतर से कचरा संग्रहण को रोकने के लिए क्या कर सकते हैं (संभवतः दूर अनुकूलित किया जा रहा से एक खाली पाश रखने के लिए) एक अनंत लूप है, जिसमें आप Thread.yield(); फोन लिखने के लिए है:

@Override 
protected void finalize() throws Throwable { 
    while (true) { 
     Thread.yield(); 
    } 
} 

मेरे यहां संदर्भ Elliot Back द्वारा एक लेख है, जिसमें इस विधि द्वारा स्मृति रिसाव को मजबूर करने का वर्णन किया गया है।

बस एक और तरीका जिसमें अंतिमकरण विधियां हैं।

+1

पर चाल चलाने के लिए अंतिम रूप() का उपयोग न करें, मुझे लगता है कि बिंदु यह नहीं था कि "थ्रेड.इल्ड()" कचरा संग्रह को रोकता है, लेकिन अनंत लूप ने किया - थ्रेड.इल्ड () अनंत लूप को बहुत अधिक CPU लेने से रोकने के लिए वहां जा रहा है। –

+0

@Score_ अच्छा पकड़ो! धन्यवाद, मैंने लेख को फिर से पढ़ लिया है, और मेरा जवाब संपादित किया है। फिर से धन्यवाद। – CPerkins

1

मुख्य बिंदु यह है कि यदि हम ऑब्जेक्ट नल पर इंगित वास्तविक संदर्भ चर सेट करते हैं, हालांकि हमारे पास उस ऑब्जेक्ट को इंगित करने वाले उस वर्ग के इंस्टेंस वेरिएबल हैं जो शून्य पर सेट नहीं हैं। वस्तु ... कचरा collection.if, जीसी करने के लिए वस्तु को बचाने के इस कोड का उपयोग करने के लिए स्वचालित रूप से पात्र है

public class GcTest { 

    public int id; 
    public String name; 
    private static GcTest gcTest=null; 

    @Override 
    protected void finalize() throws Throwable { 
     super.finalize(); 

     System.out.println("In finalize method."); 
     System.out.println("In finalize :ID :"+this.id); 
     System.out.println("In finalize :ID :"+this.name); 

     gcTest=this; 

    } 

    public static void main(String[] args) { 

     GcTest myGcTest=new GcTest(); 
     myGcTest.id=1001; 
     myGcTest.name="Praveen"; 
     myGcTest=null; 

     // requesting Garbage Collector to execute. 
     // internally GC uses Mark and Sweep algorithm to clear heap memory. 
     // gc() is a native method in RunTime class. 

     System.gc(); // or Runtime.getRuntime().gc(); 

     try { 
      Thread.sleep(2000); 
     } catch (InterruptedException e) { 
      e.printStackTrace(); 
     } 
     System.out.println("\n------- After called GC() ---------\n"); 
     System.out.println("Id :"+gcTest.id); 
     System.out.println("Name :"+gcTest.name); 


    } 

} 

आउटपुट:

को अंतिम रूप देने विधि में।
को अंतिम रूप देने में: आईडी: 1001
को अंतिम रूप देने में: ID: प्रवीण

------- बाद जीसी बुलाया() --------

आईडी: 1001
नाम : प्रवीण

3

Unsafe का उपयोग करने का सबसे अच्छा तरीका है, हालांकि ByteBuffer कुछ मामलों के लिए एक संभावित समाधान हो सकता है।

कीवर्ड "ऑफ-हेप" मेमोरी के लिए भी खोजें। ByteBuffer से अधिक

असुरक्षित

लाभ:

  • वस्तुओं सीधे क्रमबद्धता के लिए बिना प्रतिनिधित्व करने वाला, और इस तरह तेजी से
  • कोई सीमा नहीं, जांच रहा है ताकि तेजी से
  • स्पष्ट आवंटन रद्द नियंत्रण
  • की अनुमति देता है
  • JVM सीमासे अधिक आवंटित कर सकता है

हालांकि काम करना आसान नहीं है।विधि निम्न लेख में वर्णित है:

वे सभी के लिए निम्न चरणों से मिलकर बनता है:

  • हम एक sizeof ऑपरेटर की जरूरत है , जो असुरक्षित नहीं है। एक को कैसे पूछा गया: In Java, what is the best way to determine the size of an object?। सबसे अच्छा विकल्प की संभावना instrument एपीआई है, लेकिन यह एक जार बना सकते हैं और विशेष कमांड लाइन विकल्पों का उपयोग करने ...

  • एक बार हम sizeof है, Unsafe#allocateMemory साथ पर्याप्त स्मृति आवंटित है, जो मूल रूप से एक malloc है आप की आवश्यकता है और एक रिटर्न पता

  • ढेर ऑब्जेक्ट पर नियमित रूप से बनाएं, इसे Unsafe#copyMemory के साथ आवंटित स्मृति में कॉपी करें। ऐसा करने के लिए, आप ऑन-ढेर वस्तु का पता करने की जरूरत है, और वस्तु

  • का आकार एक Object सेट आबंटित स्मृति को इंगित करने के लिए, तो अपनी कक्षा में Object डाली।

    असुरक्षित के साथ सीधे एक चर का पता सेट करना प्रतीत नहीं होता है, इसलिए हमें ऑब्जेक्ट को सरणी या रैपर ऑब्जेक्ट में लपेटने की आवश्यकता है, और Unsafe#arrayBaseOffset या Unsafe#objectFieldOffset का उपयोग करें।

  • हो जाने के बाद, मैंने कभी मिलता है इस SEGFAULT मैं एक उदाहरण :-)

    पोस्ट करेंगे नहीं करने के लिए ByteBuffer

    freeMemory

साथ आबंटित स्मृति मुक्त असुरक्षित पर लाभ:

    जावा संस्करणों मेंस्थिर है, जबकि असुरक्षित
  • जाँच बाध्य करता है, इसलिए से ... असुरक्षित सुरक्षित है, जो मेमोरी लीक के लिए अनुमति देता तोड़ने के लिए और SIGSEGV

JLS says हो सकता है:

प्रत्यक्ष बफ़र्स की सामग्री सामान्य कचरा-एकत्रित ढेर के बाहर रह सकते हैं।पुरातन साथ उपयोग के

उदाहरण:

ByteBuffer bb = ByteBuffer.allocateDirect(8); 

bb.putInt(0, 1); 
bb.putInt(4, 2); 
assert bb.getInt(0) == 1; 
assert bb.getInt(4) == 2; 

// Bound chekcs are done. 
boolean fail = false; 
try { 
    bb.getInt(8); 
} catch(IndexOutOfBoundsException e) { 
    fail = true; 
} 
assert fail; 

संबंधित धागे:

1

मुझे आश्चर्य है अगर वे क्या जा रहे हैं पैटर्न है संसाधन पूल के साथ (जैसे नेटवर्क/डीबी कनेक्शन, या धागे के लिए) जहां आप पूल में संसाधन वापस करने के लिए अंतिम रूप का उपयोग करते हैं ताकि संसाधन धारण करने वाली वास्तविक वस्तु जीसीएड न हो।

बेवकूफ उदाहरण, जावा की तरह स्यूडोकोड में और तुल्यकालन के किसी भी प्रकार लापता:

class SlowResourceInternal { 
    private final SlowResourcePool parent; 
    <some instance data> 

    returnToPool() { 
     parent.add(this); 
    } 
} 

class SlowResourceHolder { 
    private final SlowResourceInternal impl; 

    <delegate actual stuff to the internal object> 

    finalize() { 
     if (impl != null) impl.returnToPool(); 
    } 
} 
संबंधित मुद्दे