कब GC.Collect को कॉल करना स्वीकार्य है?


166

सामान्य सलाह यह है कि आपको GC.Collectअपने कोड से कॉल नहीं करना चाहिए , लेकिन इस नियम के अपवाद क्या हैं?

मैं केवल कुछ बहुत ही विशिष्ट मामलों के बारे में सोच सकता हूं जहां यह कचरा संग्रह को मजबूर करने के लिए समझ में आता है।

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

क्या कोई अन्य मामले हैं जहां यह कॉल करने के लिए स्वीकार्य है GC.Collect?


जवाबों:


153

यदि आपके पास यह मानने का अच्छा कारण है कि वस्तुओं का एक महत्वपूर्ण समूह - विशेष रूप से जिन्हें आप पीढ़ियों 1 और 2 में होने का संदेह करते हैं - अब कचरा संग्रहण के लिए पात्र हैं, और अब छोटे प्रदर्शन हिट के संदर्भ में एकत्र करने के लिए उपयुक्त समय होगा ।

इसका एक अच्छा उदाहरण यह है कि यदि आपने एक बड़ा फ़ॉर्म बंद कर दिया है। आप जानते हैं कि सभी UI नियंत्रण अब कचरा एकत्र किया जा सकता है, और एक बहुत ही कम विराम के रूप में बंद कर दिया गया है, शायद उपयोगकर्ता के लिए ध्यान देने योग्य नहीं होगा।

UPDATE 2.7.2018

.NET 4.5 के रूप में - वहाँ है GCLatencyMode.LowLatencyऔर GCLatencyMode.SustainedLowLatency। इनमें से किसी भी मोड में प्रवेश करने और छोड़ने के दौरान, यह अनुशंसा की जाती है कि आप एक पूर्ण जीसी के साथ बाध्य करेंGC.Collect(2, GCCollectionMode.Forced)

.NET 4.6 के रूप में - GC.TryStartNoGCRegionविधि है (केवल पढ़ने के लिए मान सेट करने के लिए उपयोग किया जाता है)GCLatencyMode.NoGCRegion )। यह अपने आप में, पर्याप्त मेमोरी को मुक्त करने के प्रयास में एक पूर्ण अवरुद्ध कचरा संग्रह प्रदर्शन कर सकता है, लेकिन यह देखते हुए कि हम एक अवधि के लिए जीसी को अस्वीकार कर रहे हैं, मैं तर्क दूंगा कि पहले और बाद में पूर्ण जीसी प्रदर्शन करना भी एक अच्छा विचार है।

स्रोत: माइक्रोसॉफ्ट इंजीनियर बेन वाटसन: लेखन उच्च प्रदर्शन .NET कोड , 2 एड। 2018।

देख:


8
MS स्रोत कोड के अनुसार GC.Collect (2) कॉलिंग हर 850ms बस ठीक है। विश्वास नहीं होता? फिर बस PresentationCore.dll, MS.Internal.MemoryPressure.ProcessAdd () देखें। वर्तमान में मेरे पास एक इमेज प्रोसेसिंग ऐप है (छोटी छवियां, वास्तविक मेमोरी प्रेशर के साथ कुछ भी नहीं) जहां GC.Collect (2) को कॉल करने में 850ms से अधिक समय लगता है और इसलिए पूरा ऐप इसके द्वारा जम जाता है (ऐप जीसी में 99.7% समय बिताता है)।
बसंती 76६

36
@ springy76: एक ही स्थान पर माइक्रोसॉफ्ट द्वारा किया जा रहा मतलब यह नहीं है यह उन देने सलाह से एक अच्छी बात समझा रहा है से माइक्रोसॉफ्ट ...
जॉन स्कीट

4
मुझे वह उदाहरण पसंद नहीं है। पास होने के बाद इसे करने में क्या है? एक अच्छा उदाहरण जो मैं देख रहा हूं वह XBox या WindowsPhone पर गेम स्तर को लोड करने के बाद है। उन प्लेटफार्मों पर GC 1MB या sth को आवंटित करने के बाद चलता है। इसलिए स्तर के लोडिंग के दौरान जितना संभव हो उतना आवंटित करना अच्छा है (कुछ स्प्लैश स्क्रीन दिखाते समय) और फिर खेल के दौरान संग्रह से बचने के लिए GC.Collect करें।
पेरक

8
@Peri: फॉर्म क्लोज होने के बाद ऐसा करने की बात यह है कि आपने केवल वस्तुओं का एक गुच्छा बनाया है (नियंत्रण, वह डेटा जो आप प्रदर्शित कर रहे थे) कचरा संग्रहण के लिए योग्य है - इसलिए कॉल करके GC.Collectआप मूल रूप से कचरा संग्रहकर्ता को बता रहे हैं जिसे आप जानते हैं बदलाव के लिए इससे बेहतर है। आपको उदाहरण क्यों पसंद नहीं है?
जॉन स्कीट

6
@SHCJ: GC.Collect()अनुरोध करेगा कि जीसी एक पूर्ण संग्रह करता है । यदि आप जानते हैं कि आपने पहले से लंबे समय तक जीवित वस्तुओं को कचरे के संग्रह के लिए पात्र बना दिया है और आपको लगता है कि उपयोगकर्ता को बाद में की तुलना में अब मामूली विराम पर ध्यान देने की संभावना कम है, तो यह सोचना पूरी तरह से उचित लगता है कि अब बेहतर है बाद में ऐसा होने से किसी संग्रह को संकेत देने का समय।
जॉन स्कीट

50

मैं GC.Collectकेवल तभी उपयोग करता हूं जब क्रूड प्रदर्शन / प्रोफाइलर परीक्षण रिसाव लिखता हूं ; यानी मेरे पास परीक्षण करने के लिए कोड के दो (या अधिक) ब्लॉक हैं - जैसे कुछ:

GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
TestA(); // may allocate lots of transient objects
GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
TestB(); // may allocate lots of transient objects
GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
...

इसलिए कि TestA()और TestB()संभव के रूप में इसी तरह की स्थिति के साथ चलाने के लिए - यानी TestB()सिर्फ इसलिए अंकित नहीं है क्योंकि TestAयह टिपिंग बिंदु के बहुत करीब छोड़ दिया है।

एक क्लासिक उदाहरण एक साधारण कंसोल exe होगा ( Mainउदाहरण के लिए यहां पोस्ट की जाने वाली एक विधि सॉर्ट-पर्याप्त), जो लूपेड स्ट्रिंग कॉन्फैटिनेशन और के बीच का अंतर दिखाता है StringBuilder

अगर मुझे कुछ सटीक चाहिए, तो यह दो पूरी तरह से स्वतंत्र परीक्षण होंगे - लेकिन अक्सर यह पर्याप्त होता है यदि हम व्यवहार के लिए मोटा अनुभव प्राप्त करने के लिए परीक्षणों के दौरान जीसी को कम से कम (या सामान्य) करना चाहते हैं।

उत्पादन कोड के दौरान? मुझे इसका उपयोग करना बाकी है; - पी


1
और मैं शायद "WaitForPendingFinalizers" भी जोड़ (या जो भी है) इस मामले ;-p में
मार्क Gravell

29

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

ऐसे कुछ मामले हैं जब आप स्मृति उपयोग के बारे में अधिक जानते हैं तो कचरा कलेक्टर करता है। यह एक बहु उपयोगकर्ता अनुप्रयोग, या एक ऐसी सेवा में सच होने की संभावना नहीं है जो एक समय में एक से अधिक अनुरोधों का जवाब दे रही है।

हालांकि कुछ बैच प्रकार के प्रसंस्करण में आप अधिक जानते हैं तो जीसी। उदाहरण के लिए एक आवेदन पर विचार करें।

  • कमांड लाइन पर फ़ाइल नामों की एक सूची दी गई है
  • एकल फ़ाइल संसाधित करता है, फिर परिणाम फ़ाइल पर परिणाम लिखता है।
  • फ़ाइल को संसाधित करते समय, बहुत सारी इंटरलिंक्ड ऑब्जेक्ट बनाता है जिसे तब तक एकत्र नहीं किया जा सकता है जब तक कि फ़ाइल का प्रसंस्करण पूरा न हो जाए (उदाहरणार्थ एक पार्स ट्री)
  • संसाधित की गई फ़ाइलों के बीच मैच की स्थिति नहीं रखता है

आप कर सकते हैं एक केस बनाने में सक्षम हैं (सावधानी से) परीक्षण के बाद कि आपको प्रत्येक फ़ाइल को संसाधित करने के बाद एक पूर्ण कचरा संग्रह को बाध्य करना चाहिए।

एक अन्य मामला एक सेवा है जो कुछ वस्तुओं को संसाधित करने के लिए हर कुछ मिनटों में उठता है, और सोते समय कोई भी स्थिति नहीं रखता है । फिर सोने के लिए जाने से पहले एक पूर्ण संग्रह को मजबूर करना सार्थक हो सकता है।

केवल एक संग्रह के लिए मजबूर करने पर विचार करने का समय है जब मुझे पता है कि हाल ही में बहुत सी वस्तु बनाई गई थी और वर्तमान में बहुत कम वस्तुओं को संदर्भित किया गया है।

मेरे पास एक कचरा संग्रह एपीआई होगा जब मैं अपने जीसी को मजबूर करने के बिना इस प्रकार के बारे में संकेत दे सकता हूं।

" रिको मारियानी का प्रदर्शन टिडबिट्स " भी देखें


19

एक मामला यह है कि जब आप यूनिट टेस्ट कोड की कोशिश कर रहे हैं जो WeakReference का उपयोग करता है ।


11

बड़े 24/7 या 24/6 सिस्टम में - सिस्टम जो संदेशों पर प्रतिक्रिया करता है, RPC अनुरोध या जो लगातार डेटाबेस या प्रक्रिया को प्रदूषित करता है - मेमोरी लीक की पहचान करने का एक तरीका होना उपयोगी है। इसके लिए, मैं अस्थायी रूप से किसी भी प्रसंस्करण को स्थगित करने और फिर पूर्ण कचरा संग्रह करने के लिए आवेदन में एक तंत्र जोड़ने की कोशिश करता हूं। यह सिस्टम को एक विचित्र अवस्था में डाल देता है, जहाँ शेष मेमोरी या तो वैध रूप से लंबे समय तक रहने वाली मेमोरी (कैश, कॉन्फ़िगरेशन, और c।) होती है या फिर 'लीक्ड' होती है (ऐसी वस्तुएं जो अपेक्षित नहीं हैं या जो वास्तव में निहित हैं लेकिन वास्तव में हैं)।

इस तंत्र के होने से मेमोरी उपयोग को प्रोफ़ाइल करना बहुत आसान हो जाता है क्योंकि सक्रिय प्रसंस्करण से शोर के साथ रिपोर्ट को क्लाउड नहीं किया जाएगा।

यह सुनिश्चित करने के लिए कि आपको सभी कचरा मिलें, आपको दो संग्रह करने होंगे:

GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();

पहले संग्रह के रूप में किसी भी ऑब्जेक्ट को अंतिम रूप देने के साथ अंतिम रूप दिया जाएगा (लेकिन वास्तव में कचरा इन वस्तुओं को इकट्ठा नहीं करता है)। दूसरा जीसी इन अंतिम वस्तुओं को इकट्ठा करेगा।


मैंने अभी दो-दो स्थानों में दो-पास का संग्रह देखा है, लेकिन GC.WaitForPendingFinalizers के लिए MSDN प्रलेखन में पैठ को पढ़ने के बाद जो कहता है: "जारी रखने से पहले सभी अंतिम रूप से पूर्ण होने की प्रतीक्षा करें। इस कॉल के लिए GC.WitForPendingFinalizers के बिना। नीचे दिए गए कार्यकर्ता लूप को अंतिम रूप देने वाले समय के अनुसार निष्पादित किया जा सकता है। इस कॉल के साथ, कार्यकर्ता लूप सभी फाइनल करने वालों को बुलाए जाने के बाद ही निष्पादित होता है। " मैं सिर्फ एक टच पैरानॉयड हूं। क्या आप दो पास करने के लिए एक निश्चित स्रोत के बारे में जानते हैं?
jerhewet

1
@ जेरेवेट: दो संग्रह की आवश्यकता क्यों है यह समझने की कुंजी यह समझने के साथ है कि अंतिम रूप देने वाली वस्तुओं के साथ क्या होता है। दुर्भाग्य से मेरे पास ठीक वैसा नहीं है जैसा आप पूछ रहे हैं, लेकिन इस लेख और एसओ पर इस प्रश्न के बारे में पढ़ें ।
पॉल रूआन

10

जब आप एप्लिकेशन को कचरा संग्रहकर्ता की प्रकृति के बारे में कुछ जानते हैं, तो आप GC.Collect () कॉल कर सकते हैं। यह सोचने के लिए लुभा रहा है कि, लेखक के रूप में, यह बहुत संभावना है। हालांकि, सच्चाई एक बहुत अच्छी तरह से लिखित और परीक्षण विशेषज्ञ प्रणाली के लिए जीसी मात्रा है, और यह दुर्लभ है कि आप निम्न स्तर के कोड पथों के बारे में कुछ जानते हैं जो यह नहीं करता है।

सबसे अच्छा उदाहरण मैं सोच सकता हूं कि आपके पास कुछ अतिरिक्त जानकारी हो सकती है यह एक ऐप है जो निष्क्रिय अवधि और बहुत व्यस्त अवधि के बीच चक्र करता है। आप व्यस्त अवधि के लिए सर्वोत्तम प्रदर्शन चाहते हैं और इसलिए कुछ साफ करने के लिए निष्क्रिय समय का उपयोग करना चाहते हैं।

हालांकि, जीसी अधिकांश समय वैसे भी ऐसा करने के लिए पर्याप्त स्मार्ट है।


8

स्मृति विखंडन समाधान के रूप में। मैं एक मेमोरी स्ट्रीम (नेटवर्क स्ट्रीम से रीडिंग) में बहुत अधिक डेटा लिखते समय मेमोरी अपवादों से बाहर निकल रहा था। डेटा 8K विखंडू में लिखा गया था। 128M तक पहुंचने के बाद भी बहुत सी मेमोरी उपलब्ध थी (लेकिन यह खंडित था)। GC.Collect () को कॉल करने से समस्या हल हो गई। मैं फिक्स के बाद 1G को संभालने में सक्षम था।


7

रिको मारियानी के इस लेख पर एक नज़र डालें। वह दो नियम देता है जब GC.Collect को कॉल करना है (नियम 1 है: "नहीं"):

कब कॉल करें GC.Collect ()


3
वहां पहले से ही मौजूद है। मैं ऐसा कुछ करने के बहाने खोजने की कोशिश नहीं कर रहा हूं जो आपको नहीं करना चाहिए, लेकिन मैं जानना चाहूंगा कि क्या कोई विशिष्ट मामले हैं जहां यह स्वीकार्य होगा।
ब्रायन रासमुसेन

5

एक उदाहरण जहां GC.Collect () कॉल करना लगभग आवश्यक है, जब इंटरोप के माध्यम से माइक्रोसॉफ्ट ऑफिस को स्वचालित किया जाता है। Office के लिए COM ऑब्जेक्ट स्वचालित रूप से रिलीज़ करना पसंद नहीं करते हैं और इसके परिणामस्वरूप बहुत बड़ी मात्रा में मेमोरी लेने वाले Office उत्पाद के उदाहरण हो सकते हैं। मुझे यकीन नहीं है कि यह एक मुद्दा है या डिजाइन द्वारा। इस विषय के बारे में इंटरनेट पर बहुत सारी पोस्ट हैं इसलिए मैं बहुत विस्तार में नहीं जाऊंगा।

जब इंटरॉप का उपयोग करके प्रोग्रामिंग की जाती है, तो हर एक COM ऑब्जेक्ट को मैन्युअल रूप से जारी किया जाना चाहिए, हालांकि आमतौर पर मार्शल का उपयोग होता है ।eleseComObject ()। इसके अलावा, कचरा संग्रह को मैन्युअल रूप से कॉल करना थोड़ा "साफ" करने में मदद कर सकता है। जब आप इंटरोप ऑब्जेक्ट्स के साथ काम कर रहे हों तो निम्नलिखित कोड को कॉल करना कुछ हद तक मदद करता है:

GC.Collect()
GC.WaitForPendingFinalizers()
GC.Collect()

मेरे निजी अनुभव में, ReleaseComObject के संयोजन और मैन्युअल रूप से कचरा संग्रह का उपयोग करने से कार्यालय उत्पादों, विशेष रूप से एक्सेल की मेमोरी का उपयोग बहुत कम हो जाता है।


हाँ, मैं उस .net एक्सेल एक्सेसिंग के साथ भाग गया जो कॉम ऑब्जेक्ट्स के माध्यम से भी काम करता है। यह ध्यान रखना महत्वपूर्ण है, कि यह wil DEBUG मोड में अच्छी तरह से काम नहीं करता है क्योंकि GC ऑपरेशन वहाँ सीमित हैं। यह केवल RELEASE मोड में ही काम करेगा। प्रासंगिक लिंक: stackoverflow.com/questions/17130382/…
Blechdose

5

मैं सरणी और सूची पर कुछ प्रदर्शन परीक्षण कर रहा था:

private static int count = 100000000;
private static List<int> GetSomeNumbers_List_int()
{
    var lstNumbers = new List<int>();
    for(var i = 1; i <= count; i++)
    {
        lstNumbers.Add(i);
    }
    return lstNumbers;
}
private static int[] GetSomeNumbers_Array()
{
    var lstNumbers = new int[count];
    for (var i = 1; i <= count; i++)
    {
        lstNumbers[i-1] = i + 1;
    }
    return lstNumbers;
}
private static int[] GetSomeNumbers_Enumerable_Range()
{
    return  Enumerable.Range(1, count).ToArray();
}

static void performance_100_Million()
{
    var sw = new Stopwatch();

    sw.Start();
    var numbers1 = GetSomeNumbers_List_int();
    sw.Stop();
    //numbers1 = null;
    //GC.Collect();
    Console.WriteLine(String.Format("\"List<int>\" took {0} milliseconds", sw.ElapsedMilliseconds));

    sw.Reset();
    sw.Start();
    var numbers2 = GetSomeNumbers_Array();
    sw.Stop();
    //numbers2 = null;
    //GC.Collect();
    Console.WriteLine(String.Format("\"int[]\" took {0} milliseconds", sw.ElapsedMilliseconds));

    sw.Reset();
    sw.Start();
//getting System.OutOfMemoryException in GetSomeNumbers_Enumerable_Range method
    var numbers3 = GetSomeNumbers_Enumerable_Range();
    sw.Stop();
    //numbers3 = null;
    //GC.Collect();

    Console.WriteLine(String.Format("\"int[]\" Enumerable.Range took {0} milliseconds", sw.ElapsedMilliseconds));
}

और मुझे OutOfMemoryExceptionGetSomeNumbers_Enumerable_Range पद्धति में मिला केवल मेमोरी को हटाने के लिए एक ही समाधान है:

numbers = null;
GC.Collect();

वोटिंग में कमी क्यों? मेरा जवाब एक उदाहरण है जो जीसी को कॉल करने के लिए प्रदर्शित करता है। क्या आपके पास एक बेहतर सुझाव है? आपका स्वागत है।
डैनियल बी

4

आपके उदाहरण में, मुझे लगता है कि GC.Collect को कॉल करना समस्या नहीं है, बल्कि एक डिज़ाइन समस्या है।

यदि आप अंतराल पर जागने जा रहे हैं, (निर्धारित समय) तो आपके कार्यक्रम को एक ही निष्पादन के लिए तैयार किया जाना चाहिए (कार्य को एक बार निष्पादित करें) और फिर समाप्त करें। फिर, आप निर्धारित अंतराल पर चलाने के लिए एक निर्धारित कार्य के रूप में कार्यक्रम निर्धारित करते हैं।

इस तरह, आपको अपने आप को GC.Collect, (जो आपको शायद ही कभी करना चाहिए , कभी-कभी करना चाहिए) को कॉल करने से परेशान होने की आवश्यकता नहीं है।

कहा जा रहा है कि, रिको मारियानी के पास इस विषय पर एक शानदार ब्लॉग पोस्ट है, जिसे यहाँ पाया जा सकता है:

http://blogs.msdn.com/ricom/archive/2004/11/29/271829.aspx


3

GC.Collect () कॉल करने के लिए एक उपयोगी स्थान एक इकाई परीक्षण में है जब आप यह सत्यापित करना चाहते हैं कि आप मेमोरी लीक नहीं बना रहे हैं (जैसे कि आप WeakReferences या ConditionalWeakTable, डायनामिक रूप से उत्पन्न कोड, आदि के साथ कुछ कर रहे हैं)।

उदाहरण के लिए, मेरे पास कुछ परीक्षण हैं:

WeakReference w = CodeThatShouldNotMemoryLeak();
Assert.IsTrue(w.IsAlive);
GC.Collect();
GC.WaitForPendingFinalizers();
Assert.IsFalse(w.IsAlive);

यह तर्क दिया जा सकता है कि WeakReferences का उपयोग करना अपने आप में एक समस्या है, लेकिन ऐसा लगता है कि यदि आप एक ऐसा सिस्टम बना रहे हैं जो इस तरह के व्यवहार पर निर्भर करता है तो GC.Collect () कॉल करना इस तरह के कोड को सत्यापित करने का एक अच्छा तरीका है।




2
using(var stream = new MemoryStream())
{
   bitmap.Save(stream, ImageFormat.Png);
   techObject.Last().Image = Image.FromStream(stream);
   bitmap.Dispose();

   // Without this code, I had an OutOfMemory exception.
   GC.Collect();
   GC.WaitForPendingFinalizers();
   //
}

2

कुछ स्थितियां ऐसी हैं जहां यह खेद से बेहतर है।

यहाँ एक स्थिति है।

IL rewrites का उपयोग करके C # में एक अप्रबंधित DLL को लेखक के लिए संभव है (क्योंकि ऐसी परिस्थितियां हैं जहां यह आवश्यक है)।

अब मान लीजिए, उदाहरण के लिए, DLL वर्ग स्तर पर बाइट्स की एक सरणी बनाता है - क्योंकि निर्यात किए गए कई कार्यों को ऐसे तक पहुंच की आवश्यकता होती है। DLL अनलोड होने पर क्या होता है? क्या कचरा इकट्ठा करने वाले को स्वचालित रूप से उस बिंदु पर बुलाया जाता है? मुझे नहीं पता, लेकिन एक अप्रबंधित DLL होने के नाते यह पूरी तरह से संभव है कि GC को नहीं बुलाया जाता है। और अगर इसे नहीं बुलाया गया तो यह एक बड़ी समस्या होगी। जब DLL अनलोड किया जाता है, तो भी कचरा कलेक्टर होगा - तो कोई भी संभावित कचरा एकत्र करने के लिए कौन जिम्मेदार होगा और वे इसे कैसे करेंगे? C # के कचरा संग्राहक को नियोजित करने के लिए बेहतर है। एक क्लीनअप फंक्शन (डीएलएल क्लाइंट के लिए उपलब्ध) है जहाँ क्लास लेवल वेरिएबल को नल और कचरा कलेक्टर को सेट किया जाता है।

माफी से अधिक सुरक्षित।


2

मैं अभी भी इस बारे में बहुत अनिश्चित हूँ। मैं एक अनुप्रयोग सर्वर पर 7 साल से काम कर रहा हूँ। हमारे बड़े इंस्टॉलेशन 24 जीबी रैम का उपयोग करते हैं। इसके हाइटली मल्टीथ्रेड, और GC.Collect () के लिए सभी कॉल वास्तव में भयानक प्रदर्शन मुद्दों में भाग गए।

कई थर्ड पार्टी कंपोनेंट्स ने GC.Collect () का इस्तेमाल किया जब उन्हें लगा कि यह इस समय करना सही है। इसलिए एक्सेल-रिपोर्ट्स के एक सरल समूह ने ऐप सर्वर को एक मिनट में कई बार सभी थ्रेड्स के लिए ब्लॉक कर दिया।

हमें GC.Collect () कॉल को हटाने के लिए सभी 3rd पार्टी कंपोनेंट्स को रिफलेक्टर करना था और ऐसा करने के बाद सभी ने ठीक काम किया।

लेकिन मैं Win32 पर भी सर्वर चला रहा हूं, और यहां मैंने OutOfMemoryException प्राप्त करने के बाद GC.Collect () का भारी उपयोग करना शुरू कर दिया।

लेकिन मैं इस बारे में बहुत अनिश्चित हूं, क्योंकि मैंने अक्सर देखा, जब मुझे 32 बिट पर एक ओओएम मिलता है, और मैं फिर से एक ही ऑपरेशन को चलाने के लिए फिर से प्रयास करता हूं, बिना GC.Collect () बुलाए, यह ठीक काम करता है।

एक बात मुझे आश्चर्य है कि ओओएम अपवाद ही है ... अगर मैंने .Net फ्रेमवर्क लिखा होगा, और मैं मेमोरी ब्लॉक आवंटित नहीं कर सकता, तो मैं GC.Collect (), डीफ़्रैग मेमोरी (??) का उपयोग करूँगा, फिर से कोशिश करूँगा। , और अगर मैं अभी भी एक मुफ्त मेमोरी ब्लॉक नहीं पा रहा हूं, तो मैं OOM- अपवाद को फेंक दूंगा।

या कम से कम इस व्यवहार को विन्यास योग्य विकल्प के रूप में बनाते हैं, GC.Collect के साथ प्रदर्शन के मुद्दे की कमियां।

अब मेरे पास इस तरह के बहुत सारे कोड हैं जो समस्या को "हल" करने के लिए मेरे ऐप में हैं:

public static TResult ExecuteOOMAware<T1, T2, TResult>(Func<T1,T2 ,TResult> func, T1 a1, T2 a2)
{

    int oomCounter = 0;
    int maxOOMRetries = 10;
    do
    {
        try
        {
            return func(a1, a2);
        }
        catch (OutOfMemoryException)
        {
            oomCounter++;
            if (maxOOMRetries > 10)
            {
                throw;
            }
            else
            {
                Log.Info("OutOfMemory-Exception caught, Trying to fix. Counter: " + oomCounter.ToString());
                System.Threading.Thread.Sleep(TimeSpan.FromSeconds(oomCounter * 10));
                GC.Collect();
            }
        }
    } while (oomCounter < maxOOMRetries);

    // never gets hitted.
    return default(TResult);
}

(ध्यान दें कि Thread.Sleep () व्यवहार वास्तव में एक एपिक व्यवहार है, क्योंकि हम ORM कैशिंग सेवा चला रहे हैं, और सेवा को सभी कैश्ड ऑब्जेक्ट को रिलीज़ करने में कुछ समय लगता है, अगर RAM कुछ पूर्वनिर्धारित मानों से अधिक हो। पहली बार कुछ सेकंड, और OOM की प्रत्येक घटना के लिए प्रतीक्षा समय बढ़ा है।)


एक घटक को फोन नहीं करना चाहिए GC.Collect। चूँकि इसका एप्लिकेशन वाइड इफ़ेक्ट है, केवल एप्लिकेशन को ऐसा करना चाहिए (यदि बिल्कुल भी)।
कोडइंचोज

If i would have written the .Net Framework, and i can't alloc a memory block, i would use GC.Collect(),- मुझे लगता है कि वे पहले से ही ऐसा कर रहे हैं - मैंने संकेत देखे हैं कि आंतरिक जीसी ट्रिगर में से एक मेमोरी को आवंटित करने में कुछ विफलताएं हैं।
जी। स्टोयनेव

2

आपको इसकी बहुत महंगी के बाद से GC.Collect () का उपयोग करने से बचने की कोशिश करनी चाहिए। यहाँ एक उदाहरण है:

        public void ClearFrame(ulong timeStamp)
    {
        if (RecordSet.Count <= 0) return;
        if (Limit == false)
        {
            var seconds = (timeStamp - RecordSet[0].TimeStamp)/1000;
            if (seconds <= _preFramesTime) return;
            Limit = true;
            do
            {
                RecordSet.Remove(RecordSet[0]);
            } while (((timeStamp - RecordSet[0].TimeStamp) / 1000) > _preFramesTime);
        }
        else
        {
            RecordSet.Remove(RecordSet[0]);

        }
        GC.Collect(); // AVOID
    }

टेस्ट परिणाम: CPU उपयोग 12%

जब आप इसे बदलते हैं:

        public void ClearFrame(ulong timeStamp)
    {
        if (RecordSet.Count <= 0) return;
        if (Limit == false)
        {
            var seconds = (timeStamp - RecordSet[0].TimeStamp)/1000;
            if (seconds <= _preFramesTime) return;
            Limit = true;
            do
            {
                RecordSet[0].Dispose(); //  Bitmap destroyed!
                RecordSet.Remove(RecordSet[0]);
            } while (((timeStamp - RecordSet[0].TimeStamp) / 1000) > _preFramesTime);
        }
        else
        {
            RecordSet[0].Dispose(); //  Bitmap destroyed!
            RecordSet.Remove(RecordSet[0]);

        }
        //GC.Collect();
    }

टेस्ट परिणाम: CPU उपयोग 2-3%


1

एक अन्य कारण यह है कि जब आपके पास USB COM पोर्ट पर एक SerialPort खोला जाता है, और तब USB डिवाइस अनप्लग होता है। क्योंकि SerialPort खोला गया था, संसाधन सिस्टम की रजिस्ट्री में पहले से जुड़े पोर्ट के लिए एक संदर्भ रखता है। सिस्टम की रजिस्ट्री में बासी डेटा होगा , इसलिए उपलब्ध पोर्ट की सूची गलत होगी। इसलिए पोर्ट बंद होना चाहिए।

पोर्ट पर SerialPort.Close () पोर्ट कॉलिंग डिस्पोज़ () ऑब्जेक्ट पर, लेकिन यह तब तक मेमोरी में रहता है जब तक कि कचरा संग्रह वास्तव में नहीं चलता है, जिससे रजिस्ट्री तब तक बासी बनी रहती है जब तक कि कचरा संग्रहकर्ता संसाधन जारी करने का निर्णय नहीं लेता।

से https://stackoverflow.com/a/58810699/8685342 :

try
{
    if (port != null)
        port.Close(); //this will throw an exception if the port was unplugged
}
catch (Exception ex) //of type 'System.IO.IOException'
{
    System.GC.Collect();
    System.GC.WaitForPendingFinalizers();
}

port = null;

0

यह प्रश्न के लिए प्रासंगिक नहीं है, लेकिन XSLT के लिए .NET (XSLCompiledTranform) में बदल जाता है तो आपके पास कोई विकल्प नहीं हो सकता है। एक अन्य उम्मीदवार MSHTML नियंत्रण है।


0

यदि आप 4.5 से कम .net के संस्करण का उपयोग कर रहे हैं, तो मैनुअल संग्रह अपरिहार्य हो सकता है (खासकर यदि आप कई बड़ी वस्तुओं के साथ काम कर रहे हैं)।

इस लिंक का वर्णन क्यों:

https://blogs.msdn.microsoft.com/dotnet/2011/10/03/large-object-heap-improvements-in-net-4-5/


0

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

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


0

चूंकि छोटे ऑब्जेक्ट हीप (SOH) और बड़े ऑब्जेक्ट हीप (LOH) हैं

हम GC.Collect () को SOP में डी-रेफरेंस ऑब्जेक्ट को साफ़ करने के लिए कह सकते हैं, और अगली पीढ़ी के लिए लाइव ऑब्जेक्ट को स्थानांतरित कर सकते हैं।

.Net4.5 में, हम लोबोबिग्जिहैम्पकेंडमोड का उपयोग करके LOH को भी कॉम्पैक्ट कर सकते हैं


0

यदि आप बहुत सी नई System.Drawing.Bitmapवस्तुएँ बना रहे हैं , तो गारबेज कलेक्टर उन्हें साफ़ नहीं करता है। आखिरकार GDI + को लगता है कि आप मेमोरी से बाहर चल रहे हैं और "पैरामीटर मान्य नहीं है" अपवाद को फेंक देगा। GC.Collect()हर बार कॉल करना (बहुत बार नहीं!) इस मुद्दे को हल करने के लिए लगता है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.