PDA

View Full Version : سوال: آزاد نشدن حافظه تخصيص يافته به فرم



hero4000
سه شنبه 11 اسفند 1388, 17:54 عصر
سلام به همه اساتيد
من يک برنامه دارم که براي گرفتن گزارش فرمي رو که از قبل طراحي کردم رو با فرمان new ميسازم بعد آن را نمايش ميدهم و در رويداد بسته شدن فرم فرمان Dispose فرم را اجرا ميکنم ولي متاسفانه وقتي با Task Manager به حافظه برنامه نگاه ميکنم مي بينم که عملا حافظه اي آزاد نميشود و چون هر فرم من حافظه اي در حدود 8 مگ را اشغال ميکند و اين فرمها زياد لود ميشوند سيستم خيلي سنگين مي شود
اگر ميشود ينده را راهنمائي کنيد
قبلا از راهنمائي شما متشکرم

Alirezanet
سه شنبه 11 اسفند 1388, 23:46 عصر
برای بستن فرم از Close استفاده کن .... :متفکر:
me.close

hero4000
چهارشنبه 12 اسفند 1388, 17:06 عصر
دوست عزيز کاربر خودش برنامه را مي بندد با دگمه Close فرم مشکل اين است که بعد از بسته شدن فرم حافظه آزاد نميشود

Alirezanet
چهارشنبه 12 اسفند 1388, 17:59 عصر
این شرایطی که گفتین جز شرایط استاندارد نیست .. یعنی دات نت خود به خود حافظه رو پس میگیره ... مگه اینکه ...
فکر میکنم باید یه سورس بزارین تا بتونیم مشکلتون رو حل کنیم که ببینیم مشکل از کجاست !

Open-Source
چهارشنبه 12 اسفند 1388, 19:37 عصر
فکر کنم حافظه با بستن فرم آزاد میشه ولی تسک منیجر نشون نمیده.
وقتی یه پروسس به حافظه احتیاج داشته باشه حافظه آزاد شده به اون اختصاص داده میشه.

hero4000
پنج شنبه 13 اسفند 1388, 08:21 صبح
دوست عزيز از راهنمائيتون متشکرم
ولي برنامه بنده خيلي حجيم است تازه بعد از اينکه اون رو Rar ميکنم حجمش حدود 6 مگابايت ميشود اگه ميشه راه حل ديگه اي پيشنهاد بدين.
ممنونم

Chris_Ronaldo
پنج شنبه 13 اسفند 1388, 17:36 عصر
1. آخرين سرويس پك ها استفاده كنيد. مثلا آخرين سرويس پك هاي دات نت فريم ورك ها و ويژوال استوديو
2. در زمان بستن آبجكت فرم را dispose كنيد و مقدار nothing بهش پاس بدين.

hero4000
شنبه 15 اسفند 1388, 12:24 عصر
از راهنمائي همه دوستان تشکر ميکنم
من خودم در رويداد بسته شدن فرم فرمان dispose رو اجرا کردم ولي هيچ فرقي نکرد در ضمن مقدار nothing رو هم نميتونم بهش بدم چون توي رويداد بسته شدن فرم که نميشه چون فرم هنوز در حال اجراست (و همچنين رويداد Closed ) توي تابع پروسيجر فراخواني هم (چون فرم بصورت ديالوگ باز نميشه ) اگر بنويسم فرم هنوز باز نشده بسته ميشه
ورژن دات نت من هم 3.5 است و ويژوال استديوم هم 2008 است
در مورد اون دوستمون هم که گفتند Task Manager نشون نميده ولي حافظه آزاد شده من قبلا تست کردم و بعد از اينکه چندين مرتيه فرم را باز و بسته ميکنم کم کم ويندوز سنگين ميشه و احتمالا حافظه آزاد نميشه
باز هم از راهنمائي همه دوستان متشکرم

Rejnev
شنبه 15 اسفند 1388, 13:25 عصر
سلام

یعنی دات نت خود به خود حافظه رو پس میگیره
به عنوان مثال شما این query رو در sql اجرا کنید و بعد یک کوئری سبکتر رو خواهید دید که حافظه از sql گرفته نمیشه.



select a.* , b.* from sys.Messages a, sys.messages b


حدود 90 میلیارد رکورد بر میگردونه که دو سه روزی طول میکشه تموم بشه(البته اگر رم جواب بده)
بعد از یک دقیقه stop کنید و بعد یک کوئری خالی رو اجرا کنید. خواهید دید که حافظه گرفته نمیشه
مکانیزم پس گرفتن حافظه توسط خود دات نت انجام میشه.(garbage collection)

Alirezanet
دوشنبه 17 اسفند 1388, 17:32 عصر
کنترل Procees هم توی دات نت هست .. خوب میتونی از اون استفاده کنی و توی فرم Closing از Ram خارج کنی فرمتو ...
نحوه کار کردن با این کنترل هم یه سرچ بزنی توضیحات (البته سایتهای English) توضیح داره!

mehdi.mousavi
دوشنبه 17 اسفند 1388, 17:45 عصر
سلام به همه اساتيد من يک برنامه دارم که براي گرفتن گزارش فرمي رو که از قبل طراحي کردم رو با فرمان new ميسازم بعد آن را نمايش ميدهم و در رويداد بسته شدن فرم فرمان Dispose فرم را اجرا ميکنم ولي متاسفانه وقتي با Task Manager به حافظه برنامه نگاه ميکنم مي بينم که عملا حافظه اي آزاد نميشود و چون هر فرم من حافظه اي در حدود 8 مگ را اشغال ميکند و اين فرمها زياد لود ميشوند سيستم خيلي سنگين مي شود اگر ميشود ينده را راهنمائي کنيد قبلا از راهنمائي شما متشکرم

سلام.
حافظه مورد استفاده در برنامه های .NET خودش به چند بخش تقسیم میشه. برای آشنایی با هر یک و اینکه چطور مشکلتون رو حل کنید، به "مجله برنامه نویس، شماره 3، مقاله بررسی میزان حافظه مورد استفاده در برنامه های .NET" رجوع کنید. توی این مقاله، با ابزاری مثل VADump آشنا میشید و اینکه چطور از PerfMonitor استفاده کنید تا میزان حافظه مورد استفاده رو درست تشخیص بدید و چطور مشکلتون رو حل کنید.

موفق باشید.

پاورقی: هر فرم شما حاوی چه جور اطلاعاتی هستش که 8 مگابایت از حافظه رو بخودش اختصاص میده؟؟؟

hero4000
سه شنبه 18 اسفند 1388, 17:38 عصر
دوست عزيز ضمن تشکر از شما فرم بنده شامل گريد جانوس -- فيلتر اديتور جانوس و گريد پروپرتيس و... و يکسري دستورات بسيار طولاني و همچنين در هر گريد حدود 5000 رديف معمولا ريخته ميشود
من اصلا زبان انگليسيم خوب نيست اگه بتونيد فارسي توضيحي محبت کنيد ممنون ميشم

mehdi.mousavi
سه شنبه 18 اسفند 1388, 18:03 عصر
دوست عزيز ضمن تشکر از شما فرم بنده شامل گريد جانوس -- فيلتر اديتور جانوس و گريد پروپرتيس و... و يکسري دستورات بسيار طولاني و همچنين در هر گريد حدود 5000 رديف معمولا ريخته ميشود من اصلا زبان انگليسيم خوب نيست اگه بتونيد فارسي توضيحي محبت کنيد ممنون ميشم

زبان انگلیسی؟ متوجه نمیشم. مقاله ای که عنوان کردم فارسی هستش و میتونید اونو رایگان از اینجا Download کنید (http://barnamenevis.org/forum/downloads.php?do=cat&id=6).

سلام.
در هر حال، برای Load کردن داده ها، در Data Layer از چه مکانیزمهایی استفاده کرده اید؟ آیا داده ها رو در DataSet میریزید و سپس به کنترلها Bind می کنید؟ یا Custom Object هایی دارید و داده ها رو از طریق اونها به UI میدید؟ حل این معمایی که مطرح کرده اید، بدون بررسی کدهای شما، تقریبا غیر ممکن هستش...

موفق باشید.

hero4000
چهارشنبه 19 اسفند 1388, 16:53 عصر
ببخشيد منظورم از انگليسي خطاب به آقاي Alirezanet بود نه به شما سوء تفاهم نشه
داده ها را نيز من در DataSet ميريزم و بعد Bind مي کنم و تمام عمليات با کد نويسي انجام ميشه و روي فرم فقط گريد جانوس و فيلتر اديتورش هست مابقي با کد نويسي لود ميشن حتي من چند فرم ديگه دارم که اونها هم بعد از انتخاب دستور مربوطه با کد نويسي ساخته ميشن ولي در هر صورت چه اون فرمها رو اجرا کنم و چه نکنم باز هم همونقدر حافظه اشغال ميمونه
شرمندم که نميتونم کدها رو در اختيارتون قرار بدم آخه برنامه خيلي زياد و کاربردي هستش
باز هم متشکرم

Alirezanet
یک شنبه 23 اسفند 1388, 01:19 صبح
ببین یه مقاله برات گذاشتم که امیدوارم مشکلت رو حل کنه ...

در اين مقاله به طور خلاصه به نحوه عملکرد زباله روب (Garbage Collector) و استفاده از آن در برنامه مي پردازم.
وقتي برنامه اي اجرا مي شود اشيا به وجود مي آيند و مقداري از حافظه را به خود اختصاص مي دهند.
هنگامي که کار ما به يک شي تمام شد و شي را Dispose کرديم و يا زماني که زمان حيات (Life Time) يک شي به پايان رسيد، حافظه اشغال شده توسط اين شي بلا فاصله آزاد نمي شود و در حقيقت در اين هنگام رويداد Finalize مربوط به شي، فراخواني نمي شود.
آزاد سازي حافظه هاي اشغال شده بي مصرف، توسط زباله روب انجام مي شود.
زباله روب معمولا در دو حالت شروع به آزاد سازي حافظه اشغال شده مي کند.
1.در حين اجراي برنامه زماني که برنامه نياز به حافظه جديدي داشته باشد و با کمبود حافظه آزاد روبرو شود، زباله روب شروع به کار کرده و تمام حافظه هايي که توسط برنامه اشغال شده اند را نشانه گذاري مي کند. گروهي از اين حافظه ها در حال حاضر توسط برنامه در حال استفاده هستند و گروهي ديگر قبلا استفاده شده اند و اکنون ديگر قابل دسترسي و استفاده نيستند. (مانند اشيايي که در يک ساب روتين ايجاد شده اند و فراخواني ساب روتين به پايان رسيده باشد). پس از اينکه نشانه گذاري به پايان رسيد، زباله روب شروع به آزاد سازي حافظه هايي که به عنوان حافظه اشغال شده بي مصرف ، نشانه گذاري شده اند مي کند.
2.زماني که اجراي برنامه به پايان مي رسد که در اين حالت زباله روب شروع به کار کرده و کل حافظه اي که توسط برنامه اشغال شده بود را آزاد مي کند.
در حالت عادي بهتر است که ما در کار زباله روب دخالت نکنيم و بگذاريم که .DotNET Framework وظيفه مديريت حافظه رو بر عهده بگيرد.
ولي در پاره اي از موارد ما احتياج پيدا مي کنيم که زباله روب را در هنگام اجراي برنامه فراخواني کنيم تا راندمان و کارايي برنامه بالا برود.
مثلا تصور کنيد که برنامه اي داريم که هنگام اجرا، تعداد بسيار زيادي از اشيا را به وجود آورده و سپس آنها را آزاد مي کند و عملکرد برنامه به صورتي است که نياز داريم مدت زيادي در حال اجرا باشد. نتيجه اين مي شود که پس از مدتي حافظه بسيار زيادي توسط برنامه اشغال مي شود که مي تواند در کارايي سيستم و عملکرد ساير برنامه هايي که در حال اجرا هستند تأثير منفي بگذارد. (دقت داشته باشيد که به طور معمول تا زماني که برنامه بتواند حافظه جديد از سيستم بگيرد، عمل آزاد سازي حافظه هاي اشعال شده بي مصرف، توسط زباله روب انجام نمي شود)
در اين گونه مواقع ما نياز پيدا مي کنيم که هر از چند گاهي درهنگام اجراي برنامه ، حافظه هاي اشغال شده ي بي مصرف را آزاد کنيم و درحقيقت ، زباله روب را وادار سازيم تا اين عمل را انجام دهد.
در اين قسمت برنامه اي خواهيم نوشت که مطالب فوق را در بر گرفته و نحوه پياده سازي آن را نشان خواهم داد.
شروع :
يک پروژه از نوع Windows Application ايجاد کرده و دو دکمه به نام هاي btnAllocateObject و btnForceGarbageCollection به فرم اضافه کنيد.
در رويداد کليک مربوط به دکمه btnAllocateObject قطعه کد زير را بنويسيد.

' Create an object.
Private Sub btnAllocateObject_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnAllocateObject.Click
Dim obj As New TestClass
obj.ObjectNumber = m_ObjectNumber
MessageBox.Show("Created object " & m_ObjectNumber)
m_ObjectNumber += 1
End Sub
همانطور که مشاهده مي کنيد ما يک شي از نوع کلاس TestClass که در ادامه به تشريح آن مي پردازم ايجاد نموده و عضو ObjectNumber آن را مقدار دهي مي کنيم.
اکنون در رويداد کليک مربوط به کنترل btnForceGarbageCollection قطعه کد زير را بنويسيد.


' Collect all garbage generations.
Private Sub btnForceGarbageCollection_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnForceGarbageCollection.Click
GC.Collect()
MessageBox.Show("Done")
End Sub

با اجراي دستود GC.Collect ، عمل زباله روبي (Garbage Collection) آغاز مي گردد.
عمل زباله روب به اين شکل است که متد Finalize مربوط به اشيايي که بايد حافظه آن ها آزاد گردد را فراخواني مي کند. براي نشان دادن اين رويه، ما ساب روتين Finalize مربوط به کلاس TestClass را Override مي کنيم.


Public Class TestClass
Public ObjectNumber As Integer
' Display a finalization message.
Protected Overrides Sub Finalize()
MyBase.Finalize()
MessageBox.Show("Finalizing " & ObjectNumber)
End Sub
End Class

کار تمام شد.
براي امتحان برنامه آن را اجرا کنيد و چند دفعه دکمه btnAllocateObject را کليک کنيد. مشاهده مي کنيد که هر بار يک شي از نوع کلاس TestClass ايجاد شده و عضو ObectNumber آن مقدار دهي مي شود.
اکنون دکمه btnForceGarbageCollection را کليک کنيد. مشاهده مي کنيد که زباله روب در حقيقت متد Finalize هر يک از اشيايي که قبلا ايجاد نموده ايم را فراخواني مي کند و مقداري را که ما به عضو ObectNumber هر شي اختصاص داديم را مشاده مي کنيد.

hero4000
یک شنبه 23 اسفند 1388, 09:12 صبح
شرمنده

ولي اين مقاله هم مشکلم رو حل نکرد وقتي فرمان Gc.Collect رو هم ميزنم هيچي از حافظه اشغال شده کم نميشه

Alirezanet
یک شنبه 23 اسفند 1388, 18:26 عصر
من قبلا یه همچین مشکلی رو داشتم ...
مشکلم این بود که فرم از حافظه خارج میشد ولی اطلاعات و فایلهایی که فرم باز کرده بود خارج نمیشدند ! مثلا یه فایل Xml توی یه فرم باز میکردم وقتی میبستمش فرم آزاد میشد ولی چون کدهام مشکل داشت فایلها و مثلا TreeView های توی فرمم تو حافظه مقدارشون میموند . شاید مشکل شما هم همین باشه ! ... اگه آره پیشنهاد میکنم که تک تک آیتم هایی که حافظه اشغال میکنند رو توی بلوک Using بزاری و با یکسری تغییر کد و Try بتونی همش رو تک تک از حافظه خارج کنی ...
من مشکلم رو به این روش کاملا حل کردم !