मेरी उम्मीदों के खिलाफ, निम्नलिखित कार्यक्रमपहुंचा नहीं जा सकता वस्तुओं कचरा एकत्र नहीं किया जा सकता
import java.lang.ref.WeakReference;
import java.util.Arrays;
import java.util.List;
public class StackTest {
public static void main(String[] args) {
Object object1 = new Object();
Object object2 = new Object();
List<Object> objects = Arrays.asList(object1, object2);
WeakReference<Object> ref1 = new WeakReference<>(object1);
WeakReference<Object> ref2 = new WeakReference<>(object2);
for (Object o : objects) {
System.out.println(o);
}
objects = null;
object1 = null;
object2 = null;
System.gc();
System.gc();
System.gc();
System.out.println("ref1: " + ref1.get());
System.out.println("ref2: " + ref2.get());
}
}
अभी भी
ref1: [email protected]
ref2: [email protected]
object1
और object2
अर्थ जीसी एड नहीं कर रहे हैं बाहर प्रिंट करता है।
हालांकि, प्रोग्राम से for
पाश को हटाते समय, वे ऑब्जेक्ट्स जीसी-एड और प्रोग्राम प्रिंट हो सकते हैं।
ref1: null
ref2: null
एक अलग विधि से for
पाश आगे बढ़ते ही प्रभाव पड़ता है: वस्तुओं कार्यक्रम के अंत में जीसी एड कर रहे हैं।
मुझे क्या संदेह है कि यह हो रहा है कि for
लूप उन वस्तुओं को ढेर पर संग्रहीत करता है, और बाद में उन्हें हटा नहीं देता है। और चूंकि वस्तु अभी भी ढेर पर मौजूद है, यह जीसी-एड नहीं हो सकती है।
बाइट कोड को देखते हुए (जो मैं वास्तव में उस पर अच्छा नहीं कर रहा हूँ) इस परिकल्पना का समर्थन करने के लिए लगता है:
53: invokeinterface #6, 1 // InterfaceMethod java/util/List.iterator:()Ljava/util/Iterator;
58: astore 6
60: aload 6
62: invokeinterface #7, 1 // InterfaceMethod java/util/Iterator.hasNext:()Z
67: ifeq 90
70: aload 6
72: invokeinterface #8, 1 // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
77: astore 7
79: getstatic #9 // Field java/lang/System.out:Ljava/io/PrintStream;
82: aload 7
84: invokevirtual #10 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
87: goto 60
मैं astore
आदेश देखें, लेकिन मैं बाइट कोड जहां में एक जगह का पता नहीं कर सका उनको ढेर से हटा दिया जाता है।
हालांकि, मैं दो मेरी सिद्धांत के साथ समस्या है:
- मैं क्या है कि बाइट कोड से समझ में आ से, मैं उम्मीद है कि
object1
ढेर (object2
द्वारा ओवरराइट) से निकाल दिया जाता है, और केवल पिछले लूप में एक्सेस किया गया ऑब्जेक्ट (object2
) जीसी-एड नहीं होगा। -
for (Object o : objects) { System.out.println(o); o = null; }
करने के लिए
for
पाश बदलने कार्यक्रम के उत्पादन में परिवर्तित नहीं होता। मैंने सोचा होगा कि उस ढेर पर वस्तु के संदर्भ को स्पष्ट कर देगा।
प्रश्न: किसी को भी क्यों कि for
-loop सुनिश्चित करता है कि उन वस्तुओं जीसी एड नहीं किया जा सकता पर एक ठोस सिद्धांत है? मेरे सिद्धांत में उनमें कुछ अंतर छेद हैं।
प्रसंग: यह समस्या है जो हम स्मृति रिसाव का पता लगाने के लिए उपयोग एक इकाई परीक्षण, Netbeans विधि NBTestCase#assertGC
के आधार पर में आई थी। यह assertGC
विधि विफल हो जाएगी जब किसी ऑब्जेक्ट को अभी भी ढेर या ढेर पर संदर्भित किया जाता है।
हमारे परीक्षण में, हम
@Test
public void test(){
List<DisposableFoo> foos = ...;
doStuffWithFoo(foos);
List<WeakReference<DisposableFoo>> refs = ...;
for(DisposableFoo foo : foos){
disposeFoo(foo);
}
foos = null;
assertGC(refs);
}
जो नाकाम रहने पर रखा, जब तक हम for
-loop हटाया तरह कोड है।
हमारे पास पहले से ही एक वर्कअराउंड है (for
- एक अलग विधि पर जाएं), लेकिन मैं समझना चाहता हूं कि हमारा मूल कोड क्यों काम नहीं करता है।
सिर्फ इसलिए कि आप 'System.gc' कहते हैं लेकिन इसका मतलब यह नहीं है कि जीसी ने खुश किया है - लेकिन मुझे यकीन है कि आप जानते हैं कि –
@ScaryWombat: मुझे पता है। असली कोड कुछ समय में पूरे सिस्टम को 'System.gc' को कॉल करने के साथ मिलाकर पूरे ढेर को भर देता है। मैंने इसे सरल रखने के लिए इस कार्यक्रम से हटा दिया। ध्यान दें कि मैं लगातार पोस्ट कोड के साथ समस्या को पुन: उत्पन्न कर सकता हूं, और लूप को हटाने के लिए लगातार काम करता है। – Robin
यदि आप पारंपरिक लूप –