۱۳۹۰/۰۸/۰۷

محاسبه مجدد ميزان مصرف حافظه‌ي برنامه‌هاي دات نت


اگر به ميزان مصرف حافظه‌ اوليه‌ي برنامه‌هاي دات نت دقت كنيم، نسبت به مثلا يك برنامه‌ي MFC چند برابر به نظر مي‌رسند و ... اين علت دارد:
زمانيكه يك برنامه‌ي مبتني بر دات نت اجرا مي‌شود، ابتدا JIT compiler شروع به كار كرده و شروع به كامپايل برنامه مي‌كند. اين بارگزاري هم در همان پروسه‌ي اصلي برنامه انجام مي‌شود. به همين جهت ميزان مصرف حافظه‌ي برنامه‌هاي دات نت عموما بالا به نظر مي‌رسد.
اكنون سؤال اينجا است كه آيا مي توان اين حافظه‌اي را كه ديگر مورد استفاده نيست (و توسط JIT compiler اخذ شده) به سيستم بازگرداند و محاسبه‌ي مجددي را در اين مورد انجام داد. پاسخ به اين سؤال را در متد ReEvaluateWorkingSet زير مي‌توان مشاهده كرد:


using System;
using System.Diagnostics;

namespace Toolkit
{
    public static class Memory
    {
        public static void ReEvaluateWorkingSet()
        {
            try
            {
                Process loProcess = Process.GetCurrentProcess();
                //it doesn't matter what you set maxWorkingSet to
                //setting it to any value apparently causes the working set to be re-evaluated and excess discarded
                loProcess.MaxWorkingSet = (IntPtr)((int)loProcess.MaxWorkingSet + 1);
            }
            catch
            {
                //The above code requires Admin privileges. 
                //So it's important to trap exceptions in case you're running without admin rights. 
            }
        }
    }
}

در اين متد ابتدا پروسه جاري دريافت شده و سپس MaxWorkingSet به يك عدد دلخواه تنظيم مي‌شود. مهم نيست كه اين عدد چه چيزي باشد، زيرا اين تنظيم سبب مي‌شود كه در پشت صحنه به شكل حساب شده‌اي حافظه‌اي كه مورد استفاده نيست به سيستم بازگردانده شود و سپس عددي كه در task manager نمايش داده مي‌شود، مجددا محاسبه گردد. همچنين بايد دقت داشت كه اين كد تنها با دسترسي مديريتي قابل اجرا است و به همين دليل وجود اين try/catch ضروري است.

نحوه استفاده از متد ReEvaluateWorkingSet در برنامه‌هاي WinForms :
فايل Program.cs را يافته و سپس در روال رويداد گردان Idle برنامه، متد ReEvaluateWorkingSet را فراخواني كنيد (مثلا هر زمان كه برنامه minimized شد اجرا مي‌شود):

//Program.cs
namespace MemUsage
{
    static class Program
    {
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main()
        {
            //...

            Application.Idle += applicationIdle;
        }

        static void applicationIdle(object sender, EventArgs e)
        {
            Memory.ReEvaluateWorkingSet();
        }
    }
}

نحوه استفاده از متد ReEvaluateWorkingSet در برنامه‌هاي WPF :
فايل App.xaml.cs را يافته و سپس در روال رويدادگردان Deactivated برنامه، متد ReEvaluateWorkingSet را فراخواني كنيد:

//App.xaml.cs

public App()
{
    this.Deactivated += appDeactivated;
}

void appDeactivated(object sender, EventArgs e)
{
     Memory.ReEvaluateWorkingSet();
}

تاثير آن هم قابل ملاحظه است (حداقل از لحاظ رواني!). تست كنيد!