क्या जावा में कचरा संग्रह करना संभव है, भले ही यह करने के लिए मुश्किल हो? मैं जानता हूं System.gc();
और Runtime.gc();
वे केवल जीसी करने के लिए सुझाव देते हैं। मैं GC को कैसे मजबूर कर सकता हूं?
क्या जावा में कचरा संग्रह करना संभव है, भले ही यह करने के लिए मुश्किल हो? मैं जानता हूं System.gc();
और Runtime.gc();
वे केवल जीसी करने के लिए सुझाव देते हैं। मैं GC को कैसे मजबूर कर सकता हूं?
जवाबों:
आपका सबसे अच्छा विकल्प कॉल करना है System.gc()
जो बस कचरा कलेक्टर को संकेत देता है कि आप इसे एक संग्रह करना चाहते हैं। बल और तत्काल संग्रह का कोई तरीका नहीं है, क्योंकि कचरा कलेक्टर गैर-नियतात्मक है।
non-deterministic == trouble
GC.Collect()
जमा नहीं होता है। जावा में gc()
करता है।
Jlibs पुस्तकालय कचरा संग्रहण के लिए एक अच्छा उपयोगिता वर्ग है । आप WeakReference ऑब्जेक्ट्स के साथ एक निफ्टी छोटी चाल का उपयोग करके कचरा संग्रह को मजबूर कर सकते हैं।
जूलिब से RuntimeUtil.gc () :
/**
* This method guarantees that garbage collection is
* done unlike <code>{@link System#gc()}</code>
*/
public static void gc() {
Object obj = new Object();
WeakReference ref = new WeakReference<Object>(obj);
obj = null;
while(ref.get() != null) {
System.gc();
}
}
PhantomReference
साथ उपयोग करें ReferenceQueue
और फिर आपको अंतिम रूप देने के बाद सूचित किया जाएगा, लेकिन फिर भी सफाई से पहले। अंत में, भले ही आपको सफलतापूर्वक पता चला हो कि इस ऑब्जेक्ट के लिए मेमोरी को पुनः प्राप्त किया गया था, फिर भी इसका मतलब हॉटस्पा जैसे जेनेरिक जीसी में बहुत कम होगा। आमतौर पर यह युवा पीढ़ी की सफाई के साथ मेल खाता था।
System.gc(); System.gc();
, लेकिन यह जानना दिलचस्प होगा कि क्या कभी इससे बेहतर काम हुआ। वास्तव में, सिर्फ यह छपाई करना कि यह कितनी बार System.gc()
पर्याप्त होगा। कभी 2 तक पहुंचने का मौका काफी पतला है।
जीसी को बाध्य करने का सबसे अच्छा (यदि न केवल) तरीका एक कस्टम जेवीएम लिखना होगा। मेरा मानना है कि कचरा संग्रहकर्ता प्लग-इन हैं, इसलिए आप शायद उपलब्ध कार्यान्वयन में से एक को चुन सकते हैं और इसे ट्वीक कर सकते हैं।
नोट: यह एक आसान जवाब नहीं है।
जावा ™ वर्चुअल मशीन टूल इंटरफेस (JVM TI) का उपयोग करके , फ़ंक्शन
jvmtiError ForceGarbageCollection(jvmtiEnv* env)
"कचरा संग्रह करने के लिए VM को बाध्य करेगा।" जेवीएम टीआई जावाटीएम प्लेटफॉर्म डिबगर आर्किटेक्चर (जेपीडीए) का हिस्सा है ।
हाँ, यह लगभग संभव है कि आपको उसी क्रम में विधियों पर कॉल करना होगा और उसी समय ये हैं:
System.gc ();
System.runFinalization ();
भले ही एक ही समय में इस दो विधियों के उपयोग को साफ करने के लिए केवल एक वस्तु हो, कचरा संग्रहकर्ता को finalise()
सौंपी गई स्मृति को मुक्त करने और क्या करने की finalize()
विधि करने के लिए अप्राप्य वस्तु की विधि का उपयोग करने के लिए मजबूर करना है।
हो सकता है कि कचरा संग्रहकर्ता का उपयोग करना एक भयानक प्रथा है क्योंकि इसके उपयोग से सॉफ्टवेयर पर अधिक भार डाला जा सकता है जो कि मेमोरी से भी खराब हो सकता है, कचरा संग्रहकर्ता के पास अपना स्वयं का धागा होता है जो कि नियंत्रण के अतिरिक्त संभव नहीं है। जीसी द्वारा उपयोग किए गए एल्गोरिथ्म में अधिक समय लग सकता है और बहुत अक्षम माना जाता है, आपको अपने सॉफ़्टवेयर की जांच करनी चाहिए अगर यह जीसी की मदद से सबसे खराब है क्योंकि यह निश्चित रूप से टूट गया है, एक अच्छा समाधान जीसी पर निर्भर नहीं होना चाहिए।
ध्यान दें: बस यह ध्यान में रखने के लिए कि यह तभी काम करेगा जब अंतिम विधि में वस्तु का पुनर्मूल्यांकन नहीं होगा, यदि ऐसा होता है तो वस्तु जीवित रहेगी, इसका पुनरुत्थान होगा जो तकनीकी रूप से संभव है।
gc()
केवल एक कचरा संग्रह चलाने का संकेत है। runFinalizers()
केवल उन वस्तुओं पर अंतिम रूप से चलता है "जिन्हें त्याग दिया गया है"। अगर जीसी वास्तव में नहीं चलती थी, तो ऐसी कोई वस्तु नहीं हो सकती ...
OutOfMemoryError के लिए प्रलेखन के तहत यह घोषणा करता है कि इसे तब तक नहीं फेंका जाएगा जब तक कि वीएम एक पूर्ण कचरा संग्रह के बाद मेमोरी को पुनः प्राप्त करने में विफल नहीं हो जाता। इसलिए यदि आप त्रुटि प्राप्त होने तक मेमोरी आवंटित करते रहते हैं, तो आप पहले से ही एक पूर्ण कचरा संग्रह को मजबूर कर देंगे।
संभवत: वह प्रश्न जो आप वास्तव में पूछना चाहते थे, "मैं उस मेमोरी को कैसे पुनः प्राप्त कर सकता हूं जो मुझे लगता है कि मुझे कचरा संग्रह द्वारा पुनः प्राप्त करना चाहिए?"
GC से मैन्युअल रूप से अनुरोध करने के लिए (System.gc () से नहीं):
.gc भविष्य के रिलीज में उन्मूलन के लिए एक उम्मीदवार है - एक सन इंजीनियर ने एक बार टिप्पणी की थी कि शायद दुनिया में बीस से भी कम लोग वास्तव में उपयोग करना जानते हैं ।gc () - मैंने कल रात कुछ काम कुछ घंटों के लिए केंद्रीय / महत्वपूर्ण पर किया था। सिक्योर-रेंडम जेनरेट किए गए डेटा का उपयोग करके डेटा-स्ट्रक्चर, कहीं-कहीं पिछले 40,000 ऑब्जेक्ट्स से vm धीमा हो जाएगा, क्योंकि यह पॉइंटर्स से बाहर चला गया था। स्पष्ट रूप से यह 16-बिट पॉइंटर टेबल पर घुट रहा था और क्लासिक "फेलिंग मशीनरी" व्यवहार को प्रदर्शित करता था।
मैंने कोशिश की -Xms और इतने पर, जब तक यह लगभग 57, xxx कुछ करने के लिए चलेगा, तब तक थोड़ा चक्कर लगाया। तब यह जीसी () (-) कैम्प ईज़ी मनी में कोड-ब्लोट की गति के बारे में ५,,१२ 57 से ५,,१२c कहने के लिए चल रहा होगा।
आपके डिजाइन को मौलिक पुन: काम करने की आवश्यकता है, शायद एक स्लाइडिंग विंडो दृष्टिकोण।
आप कमांड लाइन से GC को ट्रिगर कर सकते हैं। यह बैच / कोंट्राब के लिए उपयोगी है:
jdk1.7.0/bin/jcmd <pid> GC.run
देख :
कचरा संग्रहण के बारे में जेवीएम विनिर्देश कुछ विशिष्ट नहीं कहता है। इसके कारण, विक्रेता अपने तरीके से जीसी को लागू करने के लिए स्वतंत्र हैं।
तो यह अस्पष्टता कचरा संग्रहण व्यवहार में अनिश्चितता का कारण बनती है। कचरा संग्रहण दृष्टिकोण / एल्गोरिदम के बारे में जानने के लिए आपको अपने जेवीएम विवरण की जांच करनी चाहिए। इसके अलावा व्यवहार को अनुकूलित करने के लिए भी विकल्प हैं।
यदि आपको कचरा संग्रहण के लिए मजबूर करने की आवश्यकता है, तो शायद आपको यह विचार करना चाहिए कि आप संसाधनों का प्रबंधन कैसे कर रहे हैं। क्या आप बड़ी वस्तुओं का निर्माण कर रहे हैं जो स्मृति में बनी रहती हैं? क्या आप बड़े ऑब्जेक्ट्स (उदाहरण के लिए, ग्राफिक्स क्लासेस) बना रहे हैं, जिनके पास Disposable
इंटरफ़ेस है और dispose()
जब इसके साथ कॉल नहीं किया जाता है? क्या आप एक वर्ग स्तर पर कुछ घोषित कर रहे हैं जो आपको केवल एक विधि के भीतर चाहिए?
यह बेहतर होगा यदि आप इस कारण का वर्णन करेंगे कि आपको कचरा संग्रहण की आवश्यकता क्यों है। यदि आप SWT का उपयोग कर रहे हैं, तो आप संसाधनों का निपटान कर सकते हैं जैसे कि Image
और Font
मेमोरी को मुक्त करना। उदाहरण के लिए:
Image img = new Image(Display.getDefault(), 16, 16);
img.dispose();
अपरिहार्य संसाधनों को निर्धारित करने के लिए उपकरण भी हैं।
यदि आप स्मृति से बाहर चल रहे हैं और आप प्राप्त कर रहे हैं, तो आप OutOfMemoryException
के java -Xms128m -Xmx512m
बजाय कार्यक्रम शुरू करने से जावा को उपलब्ध ढेर जगह की मात्रा बढ़ाने की कोशिश कर सकते हैं java
। यह आपको 128Mb का शुरुआती आकार और अधिकतम 512Mb देगा, जो कि मानक 32Mb / 128Mb से कहीं अधिक है।
java -Xms512M -Xmx1024M
एक और विकल्प नई वस्तुओं का निर्माण नहीं करना है।
जावा में जीसी की आवश्यकता को कम करने के लिए ऑब्जेक्ट पूलिंग दूर है।
ऑब्जेक्ट पूलिंग आमतौर पर ऑब्जेक्ट क्रिएशन (लाइट ऑब्जेक्ट्स के लिए एस्प) से अधिक तेज नहीं होने वाला है, लेकिन यह गारबेज कलेक्शन से तेज है। यदि आपने 10,000 ऑब्जेक्ट्स बनाए हैं और प्रत्येक ऑब्जेक्ट 16 बाइट्स था। कि 160,000 बाइट्स GC को पुनः प्राप्त करना है। दूसरी ओर, यदि आपको एक ही समय में सभी 10,000 की आवश्यकता नहीं है, तो आप ऑब्जेक्ट्स को रीसायकल / पुन: उपयोग करने के लिए एक पूल बना सकते हैं जो नई वस्तुओं के निर्माण की आवश्यकता को समाप्त करता है और जीसी पुरानी वस्तुओं की आवश्यकता को समाप्त करता है।
कुछ इस तरह (अप्रकाशित)। और यदि आप चाहते हैं कि यह थ्रेड सुरक्षित हो तो आप LinkedList को एक समवर्ती Linkedue के लिए स्वैप कर सकते हैं।
public abstract class Pool<T> {
private int mApproximateSize;
private LinkedList<T> mPool = new LinkedList<>();
public Pool(int approximateSize) {
mApproximateSize = approximateSize;
}
public T attain() {
T item = mPool.poll();
if (item == null) {
item = newInstance();
}
return item;
}
public void release(T item) {
int approxSize = mPool.size(); // not guaranteed accurate
if (approxSize < mApproximateSize) {
recycle(item);
mPool.add(item);
} else if (approxSize > mApproximateSize) {
decommission(mPool.poll());
}
}
public abstract T newInstance();
public abstract void recycle(T item);
public void decommission(T item) { }
}
G1 GC के साथ OracleJDK 10 पर, एकल System.gc()
संग्रह से GC को पुराने संग्रह को साफ करने का कारण होगा। मुझे यकीन नहीं है कि जीसी तुरंत चलता है। हालाँकि, GC System.gc()
किसी लूप में कई बार कॉल करने पर भी यंग कलेक्शन को क्लीन नहीं करेगा । युवा संग्रह को साफ करने के लिए जीसी प्राप्त करने के लिए, आपको new byte[1024]
बिना कॉल किए एक लूप (जैसे ) में आवंटित करना होगा System.gc()
। System.gc()
किसी कारण से कॉल करना GC को यंग कलेक्शन को साफ करने से रोकता है।
वास्तव में, मैं तुम्हें नहीं मिलता। लेकिन "अनंत वस्तु निर्माण" के बारे में स्पष्ट होने के लिए मेरा मतलब था कि मेरे बड़े सिस्टम में कोड का कुछ टुकड़ा है जो उन वस्तुओं का निर्माण करते हैं जिन्हें संभालता है और स्मृति में जीवित रहता है, मुझे वास्तव में केवल इशारे से कोड का यह टुकड़ा नहीं मिल सकता है !!
यह सही है, केवल इशारा है। आपके पास पहले से ही कई पोस्टरों द्वारा दिए गए मानक उत्तर हैं। आइए इसे एक-एक करके लें:
सही है, कोई वास्तविक jvm नहीं है - ऐसा केवल एक विनिर्देश है, कंप्यूटर विज्ञान का एक गुच्छा जो एक वांछित व्यवहार का वर्णन करता है ... मैंने हाल ही में मूल कोड से जावा ऑब्जेक्ट को आरंभीकृत करने में खोदा था। आप जो चाहते हैं उसे पाने के लिए, एकमात्र तरीका यह है कि आक्रामक अशक्तता कहा जाए। गलतियाँ करने पर गलतियाँ इतनी बुरी होती हैं कि हमें खुद को सवाल के मूल दायरे तक सीमित रखना पड़ता है:
यहां के अधिकांश पोस्टर आपको मान लेंगे कि आप एक इंटरफ़ेस पर काम कर रहे हैं, अगर हमें यह देखना होगा कि क्या आपको एक बार में पूरी वस्तु या एक वस्तु सौंपी जा रही है।
यदि आपको किसी ऑब्जेक्ट की आवश्यकता नहीं है, तो आप ऑब्जेक्ट को अशक्त कर सकते हैं, लेकिन यदि आप इसे गलत पाते हैं, तो एक शून्य सूचक अपवाद उत्पन्न होता है। मुझे यकीन है कि यदि आप NIO का उपयोग करते हैं तो आप बेहतर काम हासिल कर सकते हैं
किसी भी समय आपको या मुझे या किसी और को मिलता है: " कृपया मुझे उस घबराहट की आवश्यकता है। " यह लगभग सार्वभौमिक अग्रदूत है कि आप जिस पर काम करने की कोशिश कर रहे हैं, उसके कुल विनाश के लिए .... हमें एक छोटा सा नमूना कोड लिखें, इसमें से किसी को भी संक्षिप्त करना। वास्तविक कोड का इस्तेमाल किया और हमें अपना सवाल दिखाया।
निराश न हों। अक्सर यह क्या हल करता है आपका dba कहीं खरीदे गए पैकेज का उपयोग कर रहा है और बड़े डेटा संरचनाओं के लिए मूल डिज़ाइन को ट्वीक नहीं किया गया है।
यह बहुत आम है।
FYI करें
मेथड कॉल सिस्टम System.runFinalizersOnExit (सच) यह गारंटी देता है कि जावा शट डाउन करने से पहले अंतिम तरीके को कहा जाता है। हालाँकि, यह विधि स्वाभाविक रूप से असुरक्षित है और इसे हटा दिया गया है। एक विकल्प Runtime.addShutdownHook विधि के साथ "शटडाउन हुक" जोड़ने के लिए है।
मसर्रत सिद्दीकी
कचरा संग्रह करने के लिए कुछ अप्रत्यक्ष तरीका है। आपको बस तब तक अस्थायी वस्तुओं के साथ ढेर भरने की जरूरत है जब तक कि कचरा कलेक्टर निष्पादित नहीं होगा। मैंने वर्ग बनाया है जो इस तरह से कचरा इकट्ठा करने वालों को मजबूर करता है:
class GarbageCollectorManager {
private static boolean collectionWasForced;
private static int refCounter = 0;
public GarbageCollectorManager() {
refCounter++;
}
@Override
protected void finalize() {
try {
collectionWasForced = true;
refCounter--;
super.finalize();
} catch (Throwable ex) {
Logger.getLogger(GarbageCollectorManager.class.getName()).log(Level.SEVERE, null, ex);
}
}
public int forceGarbageCollection() {
final int TEMPORARY_ARRAY_SIZE_FOR_GC = 200_000;
int iterationsUntilCollected = 0;
collectionWasForced = false;
if (refCounter < 2)
new GarbageCollectorManager();
while (!collectionWasForced) {
iterationsUntilCollected++;
int[] arr = new int[TEMPORARY_ARRAY_SIZE_FOR_GC];
arr = null;
}
return iterationsUntilCollected;
}
}
उपयोग:
GarbageCollectorManager manager = new GarbageCollectorManager();
int iterationsUntilGcExecuted = manager.forceGarbageCollection();
मुझे नहीं पता कि यह तरीका कितना उपयोगी है, क्योंकि यह लगातार ढेर भरता है, लेकिन अगर आपके पास मिशन महत्वपूर्ण अनुप्रयोग है जो जीसी को बल देने के लिए जरूरी है - जब यह जीसी को मजबूर करने के लिए जावा पोर्टेबल तरीका हो सकता है।
मैं यहां कुछ बात जोड़ना चाहूंगा। कृपया नहीं कि जावा वर्चुअल मशीन पर चलता है और वास्तविक मशीन पर नहीं। वर्चुअल मशीन का मशीन के साथ संचार का अपना तरीका है। यह सिस्टम से सिस्टम में भिन्न हो सकता है। अब जब हम GC को कॉल करते हैं तो हम जावा के वर्चुअल मशीन को कचरा संग्राहक कहते हैं।
चूंकि कचरा कलेक्टर वर्चुअल मशीन के साथ है, इसलिए हम इसे वहां और फिर सफाई करने के लिए मजबूर नहीं कर सकते। इसके बजाय हम कचरा कलेक्टर के साथ हमारे अनुरोध को कतारबद्ध करते हैं। यह वर्चुअल मशीन पर निर्भर करता है, विशेष समय के बाद (यह सिस्टम से सिस्टम में बदल सकता है, आम तौर पर जब जेवीएम को आवंटित थ्रेशोल्ड मेमोरी भर जाती है) वास्तविक मशीन अंतरिक्ष को खाली कर देगी। : डी
निम्नलिखित कोड assertGC (...) विधि से लिया गया है। यह nondeterministic कचरा कलेक्टर को इकट्ठा करने के लिए मजबूर करने की कोशिश करता है।
List<byte[]> alloc = new ArrayList<byte[]>();
int size = 100000;
for (int i = 0; i < 50; i++) {
if (ref.get() == null) {
// Test succeeded! Week referenced object has been cleared by gc.
return;
}
try {
System.gc();
} catch (OutOfMemoryError error) {
// OK
}
try {
System.runFinalization();
} catch (OutOfMemoryError error) {
// OK
}
// Approach the jvm maximal allocatable memory threshold
try {
// Allocates memory.
alloc.add(new byte[size]);
// The amount of allocated memory is increased for the next iteration.
size = (int)(((double)size) * 1.3);
} catch (OutOfMemoryError error) {
// The amount of allocated memory is decreased for the next iteration.
size = size / 2;
}
try {
if (i % 3 == 0) Thread.sleep(321);
} catch (InterruptedException t) {
// ignore
}
}
// Test failed!
// Free resources required for testing
alloc = null;
// Try to find out who holds the reference.
String str = null;
try {
str = findRefsFromRoot(ref.get(), rootsHint);
} catch (Exception e) {
throw new AssertionFailedErrorException(e);
} catch (OutOfMemoryError err) {
// OK
}
fail(text + ":\n" + str);
स्रोत (मैंने स्पष्टता के लिए कुछ टिप्पणियाँ जोड़ी): NbTestCase उदाहरण
आप Runtime.getRuntime().gc()
उपयोगिता विधि का उपयोग या उपयोग करने का प्रयास कर सकते हैं System.gc()
नोट: ये विधियाँ GC को सुनिश्चित नहीं करती हैं। और उनका दायरा आपके आवेदन में प्रोग्रामेटिक रूप से संभालने के बजाय जेवीएम तक सीमित होना चाहिए।