PDA

View Full Version : مبتدی: مشکل در پاک نشدن حافظه رم بعد از بسته شدن پنجره فرم !!



ehsan_kabiri_33
یک شنبه 25 اسفند 1398, 11:09 صبح
سلام به همه دوستان که وقت میذارن و لطف میکنند:بوس:

بنده مبتدی هستم و یک برنامه خیلی پیچیده :متفکر: نوشتم که اطلاعات یک جدول در بانک Mysql را در یک Windows Form داخل یک DataGridView نشون میده !! به کمک Entity FrameWork 6

در پنجره اصلی برنامه ، یک DataGridView گذاشتم که جدول بانک اطلاعاتیم را نشون میده. که وقتی برنامه اجرا میشه حدود 76 مگ رم میخوره-
151462

اومدم یک فرم دوم اضافه کردم به نام جدول موقت! و با اجرای اون مجددا یک datagridview همان لیست را در پنجره جدید نشون میده. مسلما با اجرای فرم دوم مصرف رم بیشتر میشه و مقدار ان به حدود 122 مگ افزایش پیدا میکنه

151463

انتظار دارم که با بستن پنجره دوم (فرم موقت، فرم دوم) مجددا رم استفاده شده به همان مقدار اول 76 مگ بازگرده ولی این طور نمیشه-- از using , dispose , و همچنین try-finally dispose هم استفاده میکنم ولی باز هم هیچ تغییری نمیبینم و بعد از بسته شدن فرم دوم همچنان رم به اندازه 122 استفاده میشه و تازه هر بار پنجره دوم(فرم داخلی برنامه) را باز میکنم و میبندم دوباره هی رم استفاده شده زیاد میشه تا یجایی بعد از 380 مگا بایت دیگه زیاد نمیشه هر چی هم باز و بسته میکنم
151464



من کلا نمیفهمم چه اتفاقی داره میفته !! مگه نباید با using بعد از اینکه فرم داخلی بسته شد رم ازاد بشه؟؟

کلاس ارتباطی با دیتا بیس در لایه Datalayer:
public class UnitOfWork : IDisposable {
private MyFriendsRepository _myFriendsRepository;
mydatabaseEntities MyDB = new mydatabaseEntities();
public MyFriendsRepository myFriendsRepositoryProperty
{
get
{
this._myFriendsRepository = new MyFriendsRepository(MyDB);
return _myFriendsRepository;
}
}
public void Dispose()
{
MyDB.Dispose();
}
}


کدهای مربوط به فرم اول (فرم اصلی برنامه) یک قسمت برای لود شدن فرم اصلی - یک قسمت برای Button مربوط به فرم موقت (فرم دوم - پنجره دوم)


private void MainForm_Load(object sender, EventArgs e) {
UnitOfWork unitOfWorkInstance = new UnitOfWork();
dgvMainForm.DataSource = unitOfWorkInstance.myFriendsRepositoryProperty.Get AllFriends();
}


private void ButtonTemp_Click(object sender, EventArgs e)
{
using (TempForm tempFormInstance = new TempForm())
{
tempFormInstance.ShowDialog();
}
}



کد مربوط به فرم دوم (فرم موقت)
private void TempForm_Load(object sender, EventArgs e) {
using (UnitOfWork unitOfWorkInstance = new UnitOfWork())
{ dgvTempForm.DataSource = unitOfWorkInstance.myFriendsRepositoryProperty.Get AllFriends(); }


}

the king
یک شنبه 25 اسفند 1398, 12:29 عصر
سلام به همه دوستان که وقت میذارن و لطف میکنند:بوس:

بنده مبتدی هستم و یک برنامه خیلی پیچیده :متفکر: نوشتم که اطلاعات یک جدول در بانک Mysql را در یک Windows Form داخل یک DataGridView نشون میده !! به کمک Entity FrameWork 6

در پنجره اصلی برنامه ، یک DataGridView گذاشتم که جدول بانک اطلاعاتیم را نشون میده. که وقتی برنامه اجرا میشه حدود 76 مگ رم میخوره-
اومدم یک فرم دوم اضافه کردم به نام جدول موقت! و با اجرای اون مجددا یک datagridview همان لیست را در پنجره جدید نشون میده. مسلما با اجرای فرم دوم مصرف رم بیشتر میشه و مقدار ان به حدود 122 مگ افزایش پیدا میکنه
انتظار دارم که با بستن پنجره دوم (فرم موقت، فرم دوم) مجددا رم استفاده شده به همان مقدار اول 76 مگ بازگرده ولی این طور نمیشه-- از using , dispose , و همچنین try-finally dispose هم استفاده میکنم ولی باز هم هیچ تغییری نمیبینم و بعد از بسته شدن فرم دوم همچنان رم به اندازه 122 استفاده میشه و تازه هر بار پنجره دوم(فرم داخلی برنامه) را باز میکنم و میبندم دوباره هی رم استفاده شده زیاد میشه تا یجایی بعد از 380 مگا بایت دیگه زیاد نمیشه هر چی هم باز و بسته میکنم
من کلا نمیفهمم چه اتفاقی داره میفته !! مگه نباید با using بعد از اینکه فرم داخلی بسته شد رم ازاد بشه؟؟

نه دقیقا. سیستم عامل مالک منابع حافظه است و هر پروسه ای که نیاز به حافظه داشته باشه از سیستم عامل درخواستش می کنه.
در بعضی زبان ها که خروجی کامپایلرشون ماشین مجازی و مدیریت حافظه خودکار نداره، حافظه داخل برنامه مستقیما از سیستم عامل تامین شده و
حافظه ای که توسط برنامه آزاد میشه رو مستقیما و فوری برمیگردونیم به سیستم عامل.
اما در زبان های تجت NET. ما ماشین مجازی داریم، برنامه شما مستقیما و در ماشین واقعی اجرا نمیشه. یک محیط مدیریت شده مجازی هست و حافظه برنامه شما هم جزئی از اون ماشین مجازی است.
برای برنامه شما سیستم مدیریت حافظه خودکار داریم، حافظه مدیریت شده داریم و GC ای داریم که مسئول مدیریت این حافظه های بلا استفاده است.
بعد از اینکه برنامه شما حافظه ای رو آزاد کرد، مدت زمانی این حافظه بلااستفاده در اختیار GC میمونه، شما دیگه بهش دسترسی ندارید اما جزو حافظه تخصیص یافته به برنامه شما مونده.
مدت زمان تاخیر ممکنه چند ثانیه باشه، ممکنه چند دقیقه. فورا به سیستم عامل برگردونده نمیشه، یعنی GC در حالت عادی عجله ای برای آزاد سازی حافظه بلااستفاده نداره.
شما می توانید با ()GC.Collect از GC درخواست کنید که لطفا حافظه اشیاء بلااستفاده رو آزاد کن اما اولا به این معنی نیست که حتما الان وقت مناسبی برای اینکار بوده و ثانیا به این معنی نیست که GC مطیع درخواست شما باشه، شما از GC صرفا می توانید درخواست کنید، دستور نمی دهید. GC مستقل از برنامه شما است، از برنامه شما دستور نمی گیره.

مورد دیگری هم هست، Memory Leak یا نشت حافظه میتونه در هر کمپوننت و کتابخانه یا خود ویژوال استدیو یا حتی NET Framework. وجود داشته باشه. یک باگ برنامه نویسی است که منجر به این میشه که حافظه ای که زمانی تخصیص یافته در زمان مناسب آزاد نشه و همچنان بلااستفاده رها بشه. در خود حافظه مدیریت شده که شما با کد #C می نویسید احتمال Memory Leak کمه اما برخی کمپوننت ها ممکنه به سادگی خارج از حافظه مدیریت شده منبعی درخواست کرده باشند و آزادش نکنند و کاری هم از دست شما ساخته نباشه. اگر به موردی مشکوک باشید شاید بروز کردنش با نسخه جدیدتر مشکل رو برطرف کنه.

ShayanFiroozi
یک شنبه 25 اسفند 1398, 20:18 عصر
نه دقیقا. سیستم عامل مالک منابع حافظه است و هر پروسه ای که نیاز به حافظه داشته باشه از سیستم عامل درخواستش می کنه.
در بعضی زبان ها که خروجی کامپایلرشون ماشین مجازی و مدیریت حافظه خودکار نداره، حافظه داخل برنامه مستقیما از سیستم عامل تامین شده و
حافظه ای که توسط برنامه آزاد میشه رو مستقیما و فوری برمیگردونیم به سیستم عامل.
اما در زبان های تجت NET. ما ماشین مجازی داریم، برنامه شما مستقیما و در ماشین واقعی اجرا نمیشه. یک محیط مدیریت شده مجازی هست و حافظه برنامه شما هم جزئی از اون ماشین مجازی است.
برای برنامه شما سیستم مدیریت حافظه خودکار داریم، حافظه مدیریت شده داریم و GC ای داریم که مسئول مدیریت این حافظه های بلا استفاده است.
بعد از اینکه برنامه شما حافظه ای رو آزاد کرد، مدت زمانی این حافظه بلااستفاده در اختیار GC میمونه، شما دیگه بهش دسترسی ندارید اما جزو حافظه تخصیص یافته به برنامه شما مونده.
مدت زمان تاخیر ممکنه چند ثانیه باشه، ممکنه چند دقیقه. فورا به سیستم عامل برگردونده نمیشه، یعنی GC در حالت عادی عجله ای برای آزاد سازی حافظه بلااستفاده نداره.
شما می توانید با ()GC.Collect از GC درخواست کنید که لطفا حافظه اشیاء بلااستفاده رو آزاد کن اما اولا به این معنی نیست که حتما الان وقت مناسبی برای اینکار بوده و ثانیا به این معنی نیست که GC مطیع درخواست شما باشه، شما از GC صرفا می توانید درخواست کنید، دستور نمی دهید. GC مستقل از برنامه شما است، از برنامه شما دستور نمی گیره.

مورد دیگری هم هست، Memory Leak یا نشت حافظه میتونه در هر کمپوننت و کتابخانه یا خود ویژوال استدیو یا حتی NET Framework. وجود داشته باشه. یک باگ برنامه نویسی است که منجر به این میشه که حافظه ای که زمانی تخصیص یافته در زمان مناسب آزاد نشه و همچنان بلااستفاده رها بشه. در خود حافظه مدیریت شده که شما با کد #C می نویسید احتمال Memory Leak کمه اما برخی کمپوننت ها ممکنه به سادگی خارج از حافظه مدیریت شده منبعی درخواست کرده باشند و آزادش نکنند و کاری هم از دست شما ساخته نباشه. اگر به موردی مشکوک باشید شاید بروز کردنش با نسخه جدیدتر مشکل رو برطرف کنه.

واقعا پاسخ عالی و کاملی بود :تشویق:، حتی توی StackOverflow هم پیدا نمیشه ، من فقط میخواستم بنویسم ()GC.Collect استفاده کن و زیاد در خصوص حافظه حساس نباش ، خودش مدیریت میشه ، ولی پاسخ the king از نوشتنش منصرفم کرد !
ولی دوست دارم یه نکته اضافه کنم :

شما نباید معماری برنامت جوری باشه که کل جدل رو از دیتابیس Fetch کنی ، همیشه 100 تا یا 1000 تا رکورد نیست ، شاید بعد از 1 سال شد 1 میلیون رکورد ، اونوقت عملا نرم افزار شما غیر قابل استفاده میشه ، و Memory Low در سطح سیستم عامل اتفاق میفته ، بازه کوئریتون رو کمتر کنین مثلا 100 رکورد اخیر ، یا هر چیزه دیگه.

ehsan_kabiri_33
دوشنبه 26 اسفند 1398, 08:23 صبح
با سپاس از دو دوست عزیز بابت پاسخ گویی (دکمه تشکر ندیدم)


توی اموزشهایی که در حال یادگیری هستم گفته بودند واسه مدیریت حافظه فلان جا using و فلان جا dispose و ... استفاده بشه. واسه اینکه حسش کنم اومدم یک دیتا بزرگ 20 هزار تایی ساختم که عملا حس کنم ولی نشد. وگرنه حرف شما متین که میفرمایید کوئری باید مثلا 50 تا رکورد بیاره.

بازم ممنون:لبخندساده: