c# - জিসি কলেক্ট করার সময় কি গ্রহনযোগ্য?




.net garbage-collection (15)

সাধারণ পরামর্শ হল যে আপনি GC.Collect কল করবেন না। আপনার কোড থেকে সংগ্রহ করুন, তবে এই নিয়মটির ব্যতিক্রম কী?

আমি কেবলমাত্র কয়েকটি বিশেষ ক্ষেত্রেই মনে করতে পারি যেখানে এটি একটি আবর্জনা সংগ্রহকে জোরদার করতে পারে।

একটি উদাহরণ যে স্প্রিংস মনে রাখা একটি পরিষেবা, যা অন্তর্বর্তী সময়ে জেগে ওঠে, কিছু কাজ সম্পাদন করে, এবং তারপর দীর্ঘ সময়ের জন্য ঘুমায়। এই ক্ষেত্রে, দ্রুত-থেকে-নিষ্ক্রিয় প্রক্রিয়াটিকে প্রয়োজনীয়তার চেয়ে বেশি মেমরি ধরে রাখার জন্য একটি সংগ্রহকে জোরদার করা একটি ভাল ধারণা হতে পারে।

GC.Collect কল করতে গ্রহণযোগ্য যেখানে অন্য কোন ক্ষেত্রে আছে?


GC.Collect () কে কল করার জন্য একটি দরকারী জায়গা আপনি একটি মেমরি লিক তৈরি করছেন না তা যাচাই করার জন্য একটি ইউনিট পরীক্ষায় (উদাহরণস্বরূপ, যদি আপনি ওয়েক রেফারেন্স বা শর্তাধীন উইক্যাটেবল, গতিশীলভাবে জেনারেট কোড, ইত্যাদি সহ কিছু করছেন)।

উদাহরণস্বরূপ, আমার মত কয়েকটি পরীক্ষা আছে:

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

এটি যুক্তিযুক্ত করা যেতে পারে যে ওয়েক রেফারেন্সগুলি ব্যবহার করা এবং নিজের মধ্যে একটি সমস্যা, তবে মনে হচ্ছে যে যদি আপনি এমন আচরণ তৈরি করেন যা এমন আচরণের উপর নির্ভর করে তবে GC.Collect () কে কল করা এই কোডটি যাচাই করার একটি ভাল উপায়।


GC.Collect () কে কল করার জন্য প্রায়শই প্রয়োজনীয় একটি উদাহরণ, যখন ইন্টারপের মাধ্যমে মাইক্রোসফ্ট অফিসটি স্বয়ংক্রিয়ভাবে চালানো হয়। অফিসের জন্য COM অবজেক্টগুলি স্বয়ংক্রিয়ভাবে ছেড়ে দিতে চান না এবং ফলস্বরূপ Office পণ্যগুলির উদাহরণগুলি মেমরির বিশাল পরিমাণে গ্রহণ করে। আমি এই একটি সমস্যা বা নকশা দ্বারা নিশ্চিত না। ইন্টারনেটের চারপাশে এই বিষয় সম্পর্কে প্রচুর পোস্ট আছে তাই আমি খুব বেশি বিস্তারিত জানব না।

Interop ব্যবহার করে প্রোগ্রামিং যখন, প্রতিটি একক COM বস্তু ম্যানুয়ালি ব্যবহার করা উচিত, সাধারণত Marshal.ReleseComObject ()। উপরন্তু, গার্বেজ সংগ্রহ কলিং ম্যানুয়ালি একটু "পরিষ্কার" সাহায্য করতে পারেন। আপনি যখন ইন্টারপ বস্তুর সাথে সম্পন্ন করেন তখন নিম্নলিখিত কোডটি কল করা বেশ কিছুটা সাহায্য করে বলে মনে হচ্ছে:

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

আমার ব্যক্তিগত অভিজ্ঞতার মধ্যে, রিলিজকোমবাইটের সংমিশ্রণটি ব্যবহার করে এবং নিজে আবর্জনা সংগ্রহ কলিংয়ের ফলে অফিস পণ্যগুলির বিশেষত এক্সেল ব্যবহার করে মেমরির ব্যবহার হ্রাস পায়।


আপনার উদাহরণে, আমি মনে করি GC.Collect কলিং সমস্যা নয়, বরং একটি ডিজাইন সমস্যা রয়েছে।

আপনি যদি বিরতিতে জাগতে যাচ্ছেন, (সেট টাইমস) তবে আপনার প্রোগ্রামটিকে একক এক্সিকিউশন (একবার টাস্কটি সম্পাদন করুন) করার জন্য তৈরি করা উচিত এবং তারপরে সমাপ্ত করা হবে। তারপরে, আপনি নির্ধারিত সময়ের মধ্যে চালানোর জন্য নির্ধারিত কার্য হিসাবে প্রোগ্রামটিকে সেট আপ করুন।

এই ভাবে, আপনি GC.Collect কল করে নিজেকে উদ্বিগ্ন করতে হবে না, (যা আপনাকে খুব কমই করতে হবে, যা করতে হবে)।

যে বলেন, রিকো Mariani এই বিষয়ে একটি মহান ব্লগ পোস্ট আছে, যা এখানে পাওয়া যাবে:

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


আপনি GC.Collect () কে কল করতে পারেন যখন আপনি অ্যাপ্লিকেশনটির প্রকৃতি সম্পর্কে কিছু জানেন, আবর্জনা সংগ্রাহক তা করেন না। এটা চিন্তা করার প্রলুব্ধকর যে, লেখক হিসাবে, এটি খুব সম্ভবত। যাইহোক, সত্যটি একটি প্রশংসনীয় ভাল-লিখিত এবং পরীক্ষিত বিশেষজ্ঞ সিস্টেমের জিসি পরিমাণ, এবং এটি খুব বিরল আপনি নিম্ন স্তরের কোড পথগুলি সম্পর্কে কিছু জানেন যা এটি নয়।

সেরা উদাহরণ যেখানে আমি কিছু অতিরিক্ত তথ্য থাকতে পারি তা হল একটি অ্যাপ্লিকেশন যা নিষ্ক্রিয় সময়ের এবং খুব ব্যস্ত সময়ের মধ্যে চক্র। ব্যস্ত সময়ের জন্য সর্বোত্তম পারফরমেন্সটি আপনি চান এবং তাই কিছু পরিষ্কার করার জন্য নিষ্ক্রিয় সময়টি ব্যবহার করতে চান।

যাইহোক, বেশিরভাগ সময়ই জিসি এইভাবে করতে যথেষ্ট স্মার্ট।


আমি অ্যারে এবং তালিকা কিছু কর্মক্ষমতা পরীক্ষার করছেন:

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));
}

এবং আমি GetOomeNumbers_Enumerable_Range পদ্ধতিতে OutOfMemoryException খুঁজে পেয়েছি OutOfMemoryException হ'ল OutOfMemoryException হ্রাস করা হল:

numbers = null;
GC.Collect();

আমি এখনও এই সম্পর্কে বেশ অনিশ্চিত। আমি একটি অ্যাপ্লিকেশন সার্ভারে 7 বছর ধরে কাজ করছি। আমাদের বড় ইনস্টলেশনের ব্যবহার 24 গিগাবাইট রাম। তার উচ্চাভিলাষী Multithreaded, এবং GC.Collect জন্য সব কল () সত্যিই ভয়ঙ্কর কর্মক্ষমতা সমস্যা মধ্যে দৌড়ে।

অনেক তৃতীয় পক্ষের সামগ্রী GC.Collect () ব্যবহার করে যখন তারা মনে করেছিল যে এটি এখনই এটি করার জন্য চতুর। সুতরাং এক্সেল-রিপোর্টগুলির একটি সহজ গুচ্ছ একটি মিনিটের বেশ কয়েকবার সমস্ত থ্রেডের জন্য অ্যাপ সার্ভারকে অবরোধ করে।

GC.Collect () কলগুলি সরিয়ে দেওয়ার জন্য আমাদের সমস্ত তৃতীয় পক্ষের উপাদানগুলিকে পুনরায় প্রতিক্রিয়া জানাতে হয়েছিল, এবং এটি করার পরে সকলেই জরিমানা করে।

কিন্তু আমি Win32 এ সার্ভারগুলি চালাচ্ছি, এবং এখানে আমি OutOfMemoryException পাওয়ার পরে GC.Collect () এর ভারী ব্যবহার করতে শুরু করেছি।

কিন্তু আমিও এটি সম্পর্কে নিশ্চিত নই, কারণ আমি প্রায়শই লক্ষ্য করেছি, যখন আমি 32 বিট-তে একটি OOM পাই, এবং আমি আবার একই অপারেশন চালানোর জন্য আবার চেষ্টা করি, জিসি। কলকটি (কল) ছাড়া, এটা ঠিক কাজ করে।

এক জিনিস আমি আশ্চর্য যে OOM ব্যতিক্রম নিজেই ... যদি আমি নেট ফ্রেমওয়ার্ক লিখে থাকতাম, এবং আমি একটি মেমরি ব্লক বরাদ্দ করতে পারি না, আমি 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);
}

(উল্লেখ্য যে থ্রেড। নিদ্রা (আচরণ) আচরণটি আসলেই অ্যাপ স্পেশাল আচরণ, কারণ আমরা একটি ওআরএম ক্যাশিং পরিষেবা চালাচ্ছি, এবং যদি র্যামটি কিছু পূর্বনির্ধারিত মান অতিক্রম করে তবে পরিষেবাটি সমস্ত ক্যাশেড বস্তু মুক্ত করার জন্য কিছু সময় নেয়। সুতরাং এটি অপেক্ষা করে কয়েক সেকেন্ডের মধ্যে প্রথমবার, এবং OOM প্রতিটি occurence অপেক্ষা সময় বৃদ্ধি করেনি।)


একটি মেমরি বিভাজক সমাধান হিসাবে। একটি মেমরি প্রবাহে অনেক তথ্য লেখার সময় আমি একটি মেমরি ব্যতিক্রম খুঁজে পেয়েছিলাম (একটি নেটওয়ার্ক প্রবাহ থেকে পড়া)। তথ্য 8K অংশে লিখিত ছিল। 128M পৌঁছানোর পরে অনেক মেমরি উপলব্ধ ছিল তবে ব্যতিক্রম ছিল (কিন্তু এটি ভেঙে ফেলা হয়েছিল)। কলিং জিসি। সংগ্রহ () সমস্যা সমাধান। আমি ফিক্স পরে 1G উপর হ্যান্ডেল করতে সক্ষম ছিল।


এটি প্রশ্নটির সাথে প্রাসঙ্গিক নয়, তবে XSLT- র জন্য .NET (XSLCompiledTranform) রূপান্তরিত হয় তবে আপনার কোনও বিকল্প নেই। আরেকটি প্রার্থী এমএসএইচএমএল নিয়ন্ত্রণ।


জিসি কল করার জন্য একটি ভাল কারণ ক্ষুদ্র মেমরি সহ ছোট এআরএম কম্পিউটারগুলিতে রয়েছে, যেমন রাস্পবেরি পিআই (মোনো দিয়ে চলমান)। যদি অনির্ধারিত মেমরি টুকরা সিস্টেম RAM এর বেশি ব্যবহার করে তবে লিনাক্স OS অস্থির হতে পারে। মেমরি ওভারফ্লো সমস্যাগুলি পরিত্রাণ পেতে প্রতি সেকেন্ডে (!) আমাকে জিসি কল করতে হবে এমন একটি অ্যাপ্লিকেশন আছে।

আরেকটি ভাল সমাধান বস্তু নিষ্পত্তি করা হয় যখন তারা আর প্রয়োজন হয় না। দুর্ভাগ্যবশত এটি অনেক ক্ষেত্রে এত সহজ নয়।


বড় 24/7 বা 24/6 সিস্টেমে - বার্তাগুলিতে প্রতিক্রিয়াশীল সিস্টেমগুলি, RPC অনুরোধগুলি বা অবিরত ডাটাবেস বা প্রক্রিয়াটি প্রক্রিয়া করে - এটি মেমরি লিকগুলি সনাক্ত করার উপায় আছে। এর জন্য, আমি অস্থায়ীভাবে কোনও প্রক্রিয়াকরণ স্থগিত করার জন্য এবং সম্পূর্ণ আবর্জনা সংগ্রহ সঞ্চালনের জন্য আবেদনটিতে একটি প্রক্রিয়া যুক্ত করতে ঝোঁক। এটি সিস্টেমে একটি কোমল অবস্থানে রাখে যেখানে মেমরি অবশিষ্ট থাকে বৈধভাবে দীর্ঘস্থায়ী মেমরি (ক্যাশে, কনফিগারেশন, এবং সি।) বা অন্যথায় 'ফুটো' (বস্তুগুলি যা প্রত্যাশিত না হয় বা মূলত মূল হতে চান তবে আসলেই হয়) রাখে।

এই প্রক্রিয়াটি মেমরি ব্যবহারের প্রোফাইলটিকে অনেক সহজ করে তোলে কারণ রিপোর্টগুলি সক্রিয় প্রক্রিয়াকরণ থেকে শোরগোলের সাথে ক্লাউড করা হবে না।

আপনি সব আবর্জনা পেতে নিশ্চিত করার জন্য, আপনি দুটি সংগ্রহ সঞ্চালন করতে হবে:

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

প্রথম সংগ্রহটি চূড়ান্ত সিদ্ধান্তগুলির সাথে চূড়ান্ত করার কোনও কারণ সৃষ্টি করবে (তবে আসলে আবর্জনাগুলি এই বস্তুগুলি সংগ্রহ করে না)। দ্বিতীয় জিসি আবর্জনা এই চূড়ান্ত বস্তু সংগ্রহ করবে।


যদি আপনি 4.5 এর চেয়ে কম। এর সংস্করণ ব্যবহার করেন তবে ম্যানুয়াল সংগ্রহ অনিবার্য হতে পারে (বিশেষত যদি আপনি অনেকগুলি বড় বস্তু নিয়ে কাজ করছেন)।

এই লিঙ্কটি কেন বর্ণনা করে:

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


যেহেতু ছোট বস্তু হিপ (SOH) এবং বড় বস্তু হিপ (LOH)

আমরা SOP তে ডি-রেফারেন্স বস্তুটি সাফ করতে GC.Collect () কল করতে পারি এবং জীবন্ত বস্তুকে পরবর্তী প্রজন্মের দিকে সরাতে পারি।

ইন। নেট 4 .5, আমরা বড় লোকেশনহাপ কম্প্যাকশনমোড ব্যবহার করে LOH কম্প্যাক্ট করতে largeobjectheapcompactionmode


সংক্ষিপ্ত উত্তর: না!



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();
   //
}






garbage-collection