PDA

View Full Version : سوال: مشکل آزاد نشدن رم در هنگام استفاده از background worker



papeli_83
جمعه 01 شهریور 1392, 00:51 صبح
با سلام

در برنامه زیر که با background worker نوشته شده وقتی برای بار دوم دکمه start رو بزنم با همان تعداد تکرار(مثلا 5000000بار تکرار(در واقع در تکرار بالا خودشو نشون میده ) زمان بیشتری طول می کشه و در واقع با هر بار فشردن دکمه start مقدار بیشتری از رم اشغال می شه !!! (ببخشید وقت نکردم تبدیل به سی شارپ کنم )

109576

plus
جمعه 01 شهریور 1392, 01:31 صبح
به نظر نمیاد اینطور باشه....البته کد بی اشکال نیست.تبدیل متن به عدد باید قبل از دادن به For، توی متغییر جدا ریخته بشه، و همچنین، گزارش پیشرفت پروسه لزومی نداره حتما توی هر بار اجرا حلقه اعلام بشه (زمان گیره اینطوری).البته اینها ربطی به اشغال رم یا اینکه بعد از هر بار کندتر بشه نداره.

Imports System.Threading.Thread
Public Class Form1
Dim h As Double
Private Sub BackgroundWorker1_DoWork(ByVal sender As Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
For i = 0 To Val(TextBox1.Text)
h = 5 * i ^ 2 + i
BackgroundWorker1.ReportProgress((i / Val(TextBox1.Text)) * 100)
If BackgroundWorker1.CancellationPending = True Then
Exit Sub
End If
Next
End Sub

Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
If BackgroundWorker1.IsBusy = False Then
BackgroundWorker1.RunWorkerAsync()
ProgressBar1.Value = 0
Label1.Text = ""
End If
End Sub

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
BackgroundWorker1.CancelAsync()
End Sub
Private Sub BackgroundWorker1_ProgressChanged(ByVal sender As Object, ByVal e As System.ComponentModel.ProgressChangedEventArgs) Handles BackgroundWorker1.ProgressChanged
ProgressBar1.Value = e.ProgressPercentage
Label1.Text = e.ProgressPercentage.ToString + "%"
End Sub
End Class

papeli_83
جمعه 01 شهریور 1392, 02:17 صبح
به نظر نمیاد اینطور باشه....البته کد بی اشکال نیست.تبدیل متن به عدد باید قبل از دادن به For، توی متغییر جدا ریخته بشه، و همچنین، گزارش پیشرفت پروسه لزومی نداره حتما توی هر بار اجرا حلقه اعلام بشه (زمان گیره اینطوری).البته اینها ربطی به اشغال رم یا اینکه بعد از هر بار کندتر بشه نداره.

با تشکر از شما دوست عزیز

حتما متوجه شدید که این برنامه کوچیک رو برای نشون دادن مشکلم این طوری نوشتم ; البته برنامه اصلیم هم همین ساختار رو داره با تعداد زیادی حلقه تو در تو ( که البته دارای فرمول های محاسباتی ساده ای هم هست که فقط حجم کار بالاست ); همون طور که تو پست اول بهش اشاره کردم با هر بار اجرای برنامه سرعت برنامه پایین می یاد , اگه تو task mananger ویندوز بخش processes نگاه کنید می بینید ;که با هر بار اجرای برنامه مقدار بیشتری از رم اشغال می شود ( در تکرا بالا و در رم های یک یا دو , کند شدن خودشو بیشتر نشون می ده !! ) . (والا فکر کنم کند شدن مربوط به background worker باشه اما نمی دونم باید چکار کنم !!! )

در مورد گزارش پیشرفت اگه راهنماییم کنین ممنون می شم ( من همین روشو بلدم )

plus
جمعه 01 شهریور 1392, 12:09 عصر
من یک دور تا آخر رفتم و دوباره هم تا حدود 10-20 درصد رفتم مقدار RAM اشغال شده هیچ تغییری نکرد.البته اگه منظورتون در حد چند 100 بایت هست، عادیه و مشکلی پیش نمیاد؛ Garbage Collector خودش هر وقت لازم باشه حافظه رو از چیزهای اضافه خالی میکنه.
در مورد گزارش پیشرفت هم زمانی که تعداد حلقه ها میدونید بالاس (مثلا 50000) میتونید بررسی کنید زمانی که واقعا درصد پیشرفت داشته فراخوانی رو انجام بده. (مقدار درصد قبلی نگه داری بشه و هر بار درصد پیشرفت محاسبه بشه و با قبلی مقایسه بشه)

papeli_83
جمعه 01 شهریور 1392, 13:21 عصر
من یک دور تا آخر رفتم و دوباره هم تا حدود 10-20 درصد رفتم مقدار RAM اشغال شده هیچ تغییری نکرد.البته اگه منظورتون در حد چند 100 بایت هست، عادیه و مشکلی پیش نمیاد؛ Garbage Collector خودش هر وقت لازم باشه حافظه رو از چیزهای اضافه خالی میکنه.
در مورد گزارش پیشرفت هم زمانی که تعداد حلقه ها میدونید بالاس (مثلا 50000) میتونید بررسی کنید زمانی که واقعا درصد پیشرفت داشته فراخوانی رو انجام بده. (مقدار درصد قبلی نگه داری بشه و هر بار درصد پیشرفت محاسبه بشه و با قبلی مقایسه بشه)

با سلام خدمت شما وممنون از وقتی که گذاشتین

در مورد garbage collector تو چند تا سایت مطالبی راجع بهش بود ولی من متوجه نشدم طرز کارش چجوریه ! ( یعنی از چه کلاسی باید فراخوانی بشه و کجای برنامه باید استفاده بشه ) اگه ممکنه یه توضیحی بدین.

درمورد پیشرفت کار منطورتونو متوجه نشدم اگه براتون امکان داره روی همین مثال یا یه مثال از خودتون یه توضیحی بدین.

با تشکر از شما

plus
جمعه 01 شهریور 1392, 14:36 عصر
در مورد Garbage Collector (http://msdn.microsoft.com/en-us/library/system.gc.aspx)، شما معمولا نیازی ندارین تا باهاش مستقیما در ارتباط باشید، خودش کار رو انجام میده.نحوه کار و علت وجودش هم طولانی هست فقط در همین حد بگم که مکانیزمی هست که هنگامی که برنامه در حال اجراس، در پشت صحنه، هر وقت لازم ببینه، حافظه های اشغال شده ای که دیگه نیازی بهشون نیست رو آزاد میکنه.با این مکانیزم، برنامه نویس کمتر درگیر آزاد کردن حافظه های اختصاص یافته در برنامه میشه...
-
در مورد نحوه گزارش پیشرفت هم میتونید اینطوری عمل کنید:

Private Sub BackgroundWorker1_DoWork(ByVal sender As Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork

Dim oldProgress As Long
Dim upperBound As Long

oldProgress = -1
upperBound = CInt(TextBox1.Text)
For i = 0 To upperBound
h = 5 * i ^ 2 + i
Dim newProgress As Long
newProgress = CLng((CDbl(i) / upperBound) * 100)
If (newProgress <> oldProgress) Then
oldProgress = newProgress
BackgroundWorker1.ReportProgress(newProgress)
End If

If BackgroundWorker1.CancellationPending = True Then
Exit Sub
End If
Next
End Sub

از اونجایی که شما کد خاصی در For ندارین، بیشتر تاخیری که کد قبلی داشت بخاطر تعداد فراخوانی های رویداد گزارش پیشرفت بود..

sajadzare
جمعه 01 شهریور 1392, 14:47 عصر
شما می تونین بعد از فشردن دکمه اونو تا تموم شدن عملیات disable کنی تا قبل از اتمام کار دوباره فشرده نشه
button1.enabled = false

papeli_83
جمعه 01 شهریور 1392, 15:16 عصر
با سلام
ممنون از کمکتون خیلی لطف کردین

یه سوال دیگه داشتم من می خوام درصد پیشرفت کار رو روی progressbar نمایش بدم و به همین خاطر یه labbel روی progress bar قرار دادم و کدای زیر رو برای transparent کردن قرار دادم اما متاسفانه کار نمی کنه

Public Class Form1
Public Sub New()
InitializeComponent()
Dim pos As Point = PointToScreen(Label1.Location)
pos = ProgressBar1.PointToClient(pos)
Label1.Parent = ProgressBar1
Label1.Location = pos
Label1.BackColor = Color.Transparent
End Sub

البته قبلش از طریق کدنویسی و از طریق گرافیک خواستم این کار رو انجام بدم ولی متاسفانه طریقه نمایش اون مثل label کیفیت لازم رو نداشت

Private Sub BackgroundWorker1_ProgressChanged(ByVal sender As Object, ByVal e As System.ComponentModel.ProgressChangedEventArgs) Handles BackgroundWorker1.ProgressChanged
ProgressBar1.Value = e.ProgressPercentage
'Label1.Text = e.ProgressPercentage.ToString + "%"
ProgressBar1.CreateGraphics().DrawString(e.Progres sPercentage.ToString() + "%", SystemFonts.DefaultFont, New SolidBrush(ProgressBar1.ForeColor), New PointF(ProgressBar1.Width / 2 - (ProgressBar1.CreateGraphics().MeasureString(e.Pro gressPercentage.ToString() + "%", SystemFonts.DefaultFont).Width / 2.0F), ProgressBar1.Height / 2 - (ProgressBar1.CreateGraphics().MeasureString(e.Pro gressPercentage.ToString() + "%", SystemFonts.DefaultFont).Height / 2.0F)))
End Sub

این هم کل کدهام

Imports System.Threading.Thread
Public Class Form1
Public Sub New()
InitializeComponent()
Dim pos As Point = PointToScreen(Label1.Location)
pos = ProgressBar1.PointToClient(pos)
Label1.Parent = ProgressBar1
Label1.Location = pos
Label1.BackColor = Color.Transparent
End Sub
Dim h As Double
Private Sub BackgroundWorker1_DoWork(ByVal sender As Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
Dim oldProgress As Long
Dim upperBound As Long

oldProgress = -1
upperBound = CInt(TextBox1.Text)
For i = 0 To upperBound
h = 5 * i ^ 2 + i
Dim newProgress As Long
newProgress = CLng((CDbl(i) / upperBound) * 100)
If (newProgress <> oldProgress) Then
oldProgress = newProgress
BackgroundWorker1.ReportProgress(newProgress)
End If

If BackgroundWorker1.CancellationPending = True Then
Exit Sub
End If
Next
End Sub

Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
If BackgroundWorker1.IsBusy = False Then
BackgroundWorker1.RunWorkerAsync()
ProgressBar1.Value = 0
Label1.Text = ""
End If
End Sub

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
BackgroundWorker1.CancelAsync()
End Sub
Private Sub BackgroundWorker1_ProgressChanged(ByVal sender As Object, ByVal e As System.ComponentModel.ProgressChangedEventArgs) Handles BackgroundWorker1.ProgressChanged
ProgressBar1.Value = e.ProgressPercentage
Label1.Text = e.ProgressPercentage.ToString + "%"
' ProgressBar1.CreateGraphics().DrawString(e.Progres sPercentage.ToString() + "%", SystemFonts.DefaultFont, New SolidBrush(ProgressBar1.ForeColor), New PointF(ProgressBar1.Width / 2 - (ProgressBar1.CreateGraphics().MeasureString(e.Pro gressPercentage.ToString() + "%", SystemFonts.DefaultFont).Width / 2.0F), ProgressBar1.Height / 2 - (ProgressBar1.CreateGraphics().MeasureString(e.Pro gressPercentage.ToString() + "%", SystemFonts.DefaultFont).Height / 2.0F)))
End Sub
End Class

papeli_83
جمعه 01 شهریور 1392, 15:30 عصر
شما می تونین بعد از فشردن دکمه اونو تا تموم شدن عملیات disable کنی تا قبل از اتمام کار دوباره فشرده نشه
button1.enabled = false
با سلام وممنون از توجهتون

من منظورم این نبود که هنگام انجام کار دکمه فشرده بشه , بلکه وقتی کار انجام شد و دوباره کاربر خواست start کنه ( بدون بستن برنامه و شروع مجدد ) , انجام پروسه طول می کشید وهمین طور برای مراحل بعدی

plus
جمعه 01 شهریور 1392, 15:53 عصر
نوشتن متن روی Progress Bar به صورت کاملا درست و بدون اشکال موضوع دردسر داری هست، شما یا میتونی بالاش Label بگذاری، یا از کلاس Progress Bar ارث بری کنی و رفتارش رو اونطور که میخوای پیداده کنی (که کار راحتی نیست)، یا UserControl خودت رو برای این کار بنویسی و یا از کنترل های آماده استفاده کنی.