ورود

View Full Version : مشکل خارج نشدن Frame از حافظه پس از ایجاد استفاده از آن در زمان اجرا



shedayat
دوشنبه 25 اردیبهشت 1391, 20:08 عصر
سلام دوستان.
من یه Frame به پروژم اضافه کردم و تو زمان اجرا اونو Create و ازش استفاده کردم. حالا هم می خوام اونو از حافظه خارج کنم با این دستور Frame رو ایجاد می کنم:

var
FR:TFrame1;
TT:TRzTabSheet;
begin


TT:=TRzTabSheet.Create(RzPageControl1);
TT.PageControl:=RzPageControl1;
RzPageControl1.ActivePage:=TT;
fr:=TFrame1.Create(RzPageControl1);
fr.Parent:=RzPageControl1.ActivePage;
RzPageControl1.Show;
end;


همونطور که از کد مشخصه با اجرای این کد Tabsheet جدید ایجاد می شه و Frame در اون قرار می گیره.
حالا می خوام بعد از انجام کارم این Frame رو از حافظه خارج کنم که این کد رو می نویسم:


RzPageControl1.ActivePage.Free;


ولی مثل اینکه دستور اشتباهه. چون حافظه اختصاص داده شده به فریم Free نمی شه.

SAASTN
دوشنبه 25 اردیبهشت 1391, 22:16 عصر
ولی مثل اینکه دستور اشتباهه. چون حافظه اختصاص داده شده به فریم Free نمی شه.
چطور به این نتیجه رسیدی؟ کلا برگه در حال نمایش می مونه یا وقتی با دیباگ بررسی می کنی می بینی مقادیر سر جاشون هستند.
در هر صورت Free برای آزاد کردن شیئ کفایت می کنه.

shedayat
دوشنبه 25 اردیبهشت 1391, 22:34 عصر
هیچکدوم.
توی Taskmgr ویندوز حجم اشغال شده برنامه در RAM رو می بینم، وقتی با زدن یه دکمه Frame ایجاد می شه مقدار حافظه ی اشغال شده تو رم بیشتر می شه و وقتی هم با یه دکمه Free می کنم حجم برنامه به مقدار قبلی (یا نزدیک به اون) بر نمی گرده.
و وقتی هم چند بار ایجاد بشه و دوباره فری بشه حجم برنامه توی رم بالاتر می ره.

SAASTN
دوشنبه 25 اردیبهشت 1391, 22:44 عصر
Taskmgr اصلا ملاک خوبی برای مشاهده RealTime میزان حافظه اشغال شده نیست.
این تاپیک رو هم یه نگاه بکن:
http://barnamenevis.org/showthread.php?314032-%D8%A8%DB%8C%D8%B4%D8%AA%D8%B1-%D8%B4%D8%AF%D9%86-%D9%81%D8%B6%D8%A7%DB%8C-%D8%A7%D8%B4%D8%BA%D8%A7%D9%84-%D8%B4%D8%AF%D9%87-%D8%AF%D8%B1-%D8%B1%D9%85-%D8%AA%D9%88%D8%B3%D8%B7-%D8%A8%D8%B1%D9%86%D8%A7%D9%85%D9%87-%D8%A8%D9%87-%D9%85%D8%B1%D9%88%D8%B1-%D8%B2%D9%85%D8%A7%D9%86

shedayat
دوشنبه 25 اردیبهشت 1391, 22:50 عصر
خیلی ممنون. جوابم رو از لینکی که داده بودین گرفتم.
ممنون. :لبخندساده:
راستی فقط یه سوالی این وسط پیش میاد:
من وقتی با این خط :
TT:=TRzTabSheet.Create(RzPageControl1);
fr:=TFrame1.Create(RzPageControl1);




این اشیا رو Create کردم و هیچ کدی برای Free کردن این دو تا شی ننوشتم (مثلا TT.Free) چطور و چه وقت این اشیا Free می شن؟

SAASTN
دوشنبه 25 اردیبهشت 1391, 23:18 عصر
تا جایی که من می دونم دلفی فقط می تونه نشت حافظه های شما رو گزارش کنه. البته شاید ابزار های دیگه ای هم باشن. برای این که ببینی اون شیئ آزاد می شه یا نه کد زیر رو توی سورس برنامه قرار بده، یعنی از منوی Project گزینه View Source رو بزن و کد زیر رو بعد از begin بزار. بعد اون قسمتی که فکر می کنی شئی آزاد نمیشه رو اجرا کن و ببند. موقع بسته شدن برنامه یه پیام نمایش پیدا می کنه و نشت حافظه های برنامه رو به همراه کلاس هاشون و حجم هاشون رو نمایش میده. اگر پیام نمایش پیدا نکرد یعنی مشکلی وجود نداشته.
ReportMemoryLeaksOnShutdown := True;

shedayat
دوشنبه 25 اردیبهشت 1391, 23:51 عصر
منم قبل از اینکه ای سوال رو بپرسم انجام دادم و هیچ مشکلی نبود. فقط خواستم مطمئن بشم.
دست گلت درد نکنه.
متشکر.

SAASTN
سه شنبه 26 اردیبهشت 1391, 02:03 صبح
منم قبل از اینکه ای سوال رو بپرسم انجام دادم و هیچ مشکلی نبود. فقط خواستم مطمئن بشم.
آقا یه مطلبی یادم رفت بگم. برای این که اون کد درست کار کنه باید پروژت یه بار Build بشه. باز برای این که مطمئن بشی خودت یه شیئ، مثلا یه TObjectی چیزی ایجاد کن و آزادش نکن ببین گزارش می کنه یا نه.

راستی فقط یه سوالی این وسط پیش میاد:
من وقتی با این خط :
1
2
3
4
5
TT:=TRzTabSheet.Create(RzPageControl1);
fr:=TFrame1.Create(RzPageControl1);

این اشیا رو Create کردم و هیچ کدی برای Free کردن این دو تا شی ننوشتم (مثلا TT.Free) چطور و چه وقت این اشیا Free می شن؟
توضیحش تو پست پنجم تاپیک زیر هست:
http://barnamenevis.org/showthread.php?337942-%DA%86%DA%AF%D9%88%D9%86%DA%AF%DB%8C-%D8%A8%D8%B1%DA%AF%D8%B4%D8%AA-%D9%85%D9%82%D8%AF%D8%A7%D8%B1%DB%8C-%D8%A7%D8%B2-%D9%86%D9%88%D8%B9-%DA%A9%D9%84%D8%A7%D8%B3-%D8%AF%D8%B1-%D8%AA%D9%88%D8%A7%D8%A8%D8%B9

shedayat
سه شنبه 26 اردیبهشت 1391, 09:23 صبح
با کد زیر یه دکمه ایجاد کردم:

var B:TButton;
begin
B:=TButton.Create(nil);

و دیگه اونو آزاد نکردم، وقتی که فرم رو بستم Message Box نشون داد که گفته Memory Leak داری.
اما وقتی این کد رو به کد بالا اضافه کردم:
B.Parent:=Form1;
دیگه موقع بستن پیغامی مبنی بر نشت حافظه نشون نداد. یعنی اون دکمه همراه با فرم Free می شه.

حالا دوباره بر می گردیم به کد بالا:
با این توصیفات، این کد:
ReportMemoryLeaksOnShutdown := True;
اشیایی که در حین بسته شدن فرم آزاد نشدن رو نشون می ده. ولی در صورتی که من سوالم این بود که تو زمان اجرا کنترلی رو ایجاد می کنم و بعدش Free می کنم. ابزاری وجود نداره که مطمئن بشم که اون تو زمان اجرا وقتی دستور Free رو می دم آزاد می شه یا نه؟

SAASTN
سه شنبه 26 اردیبهشت 1391, 10:50 صبح
با این توصیفات، این کد اشیایی که در حین بسته شدن فرم آزاد نشدن رو نشون می ده.
اینطور نیست. اون گزارش لیست تمامی حافظه هایی که از سیستم عامل گرفته شدن ولی پس داده نشدن رو نشون میده، به عنوان مثال اگه شما هیچ شیئی ایجاد نکنی و فقط کد زیر رو اجرا کنی هم باز اون پیغام نمایش پیدا می کنه:
procedure TForm1.FormCreate(Sender: TObject);
var
P: Pointer;
begin
GetMem(P, 2000);
end;


توضیح اینکه چرا بعد از ست کردن Parent اون دکمه، دیگه پیغام نمایش پیدا نمی کنه رو تو همون تاپیکی که قبلا لینک دادم نوشتم. خلاصش این که فرم موقع آزادسازی خودش کنترلهای روی خودش رو هم آزاد می کنه. اما برای این که مطمئن بشی اون کنترل بعد از Free آزاد میشه یا نه، یه کنترل ایجاد کن و Owner یا Parentش رو ست نکن. حالا برنامه رو یه بار با Free کردن کنترل و یه بار بدون اون اجرا کن. توی شرایط اول گزارشی مبنی بر نشت حافظه نمایش پیدا نمی کنه و از اونجایی که ما پرنت کنترل رو ست نکردیم، مطمئن هستیم که اون شیئ همراه با فرم آزاد نشده پس می تونیم به این نتیجه برسیم که Free کارش رو درست انجام داده.

Felony
سه شنبه 26 اردیبهشت 1391, 23:34 عصر
اشیایی که در حین بسته شدن فرم آزاد نشدن رو نشون می ده. ولی در صورتی که من سوالم این بود که تو زمان اجرا کنترلی رو ایجاد می کنم و بعدش Free می کنم. ابزاری وجود نداره که مطمئن بشم که اون تو زمان اجرا وقتی دستور Free رو می دم آزاد می شه یا نه؟
دستور Assigned بررسی میکنه که حافظه به یک شئ اختصاص داده شده یانه ، میتونی بعد از آزاد کردن شئ مورد نظر با Assigned بررسی کنی و مطمئن شئ حافظه ای بهش تخصیص پیدا نکرده ؛ در ضمن اونجور صدا زدن متد Free چندان مناسب نیست ، برای اینکه مطمئن بشی که روال آزاد سازی شئ تحت هر شرایطی حتما اجرا میشه ، عملیات آزاد سازی اشیاء رو تو بلوک try ... finally انجام بده .

vcldeveloper
جمعه 29 اردیبهشت 1391, 13:13 عصر
دستور Assigned بررسی میکنه که حافظه به یک شئ اختصاص داده شده یانه ، میتونی بعد از آزاد کردن شئ مورد نظر با Assigned بررسی کنی و مطمئن شئ حافظه ای بهش تخصیص پیدا نکرده


var
B : TObject;
begin
B := TObject.Create;
B := nil;
if Assigned(B) then
ShowMessage('Your object is still in memory')
else
ShowMessage('Your object is freed :)');
end;

پس Assigned وضعیت حافظه رو چک نمیکنه، فقط مقدار Pointer رو بررسی میکنه. اگر مقدار یک Pointer (شامل هر نوع داده ای به صورت reference کار میکنه، مثل object) مساوی nil باشه، Assigned مقدار False برگشت میده؛ حتی اگر داده مربوطه عملا از حافظه خارج نشده باشه!

shedayat
یک شنبه 28 خرداد 1391, 10:15 صبح
... در ضمن اونجور صدا زدن متد Free چندان مناسب نیست ، برای اینکه مطمئن بشی که روال آزاد سازی شئ تحت هر شرایطی حتما اجرا میشه ، عملیات آزاد سازی اشیاء رو تو بلوک try ... finally انجام بده .
کدی رو که تو پست اول نوشتم رو چطور می تونم توی try... finally بنویسم؟ چون من می خوام Frame مورد نظر روی Tabsheet ایجاد بشه و بعد از اینکه کار کاربر با اون تمام شد با دکمه Close، اون فریم Free بشه.

shedayat
پنج شنبه 15 تیر 1391, 19:37 عصر
دستور Assigned بررسی میکنه که حافظه به یک شئ اختصاص داده شده یانه




var
B : TObject;
begin
B := TObject.Create;
B := nil;
if Assigned(B) then
ShowMessage('Your object is still in memory')
else
ShowMessage('Your object is freed :)');
end;

پس Assigned وضعیت حافظه رو چک نمیکنه، فقط مقدار Pointer رو بررسی میکنه. اگر مقدار یک Pointer (شامل هر نوع داده ای به صورت reference کار میکنه، مثل object) مساوی nil باشه، Assigned مقدار False برگشت میده؛ حتی اگر داده مربوطه عملا از حافظه خارج نشده باشه!

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

shedayat
پنج شنبه 15 تیر 1391, 19:52 عصر
این مثال رو ببینید:
var b:TButton;
begin
if Assigned(b) then
ShowMessage('Assigned');
end;

تو این مثال با اینکه اسمی از Create برده نشده ولی وقتی رو دکمه کلیک میشه پیغام چاپ می شه!!!

Felony
پنج شنبه 15 تیر 1391, 20:06 عصر
از کد زیر استفاده کنید :

var
A: TButton;
begin
if IsBadReadPtr(A, sizeof(0)) then
ShowMessage('');
end;

shedayat
پنج شنبه 15 تیر 1391, 22:30 عصر
خیلی ممنون از وقتی که می زارید و پاسخ می دید. ولی اینم جواب نمی ده.
در مثال زیر ببینید با اینکه شی A رو ایجاد می کنم و آزادش نمی کنم ولی بازم اون پیغام نمایش داده نمی شه.

از کد زیر استفاده کنید :

var
A: TButton;
begin
A:=TButton.Create(nil);
if IsBadReadPtr(A, sizeof(Pointer)) then
ShowMessage('');
end;

Felony
پنج شنبه 15 تیر 1391, 23:32 عصر
دوست عزیز لطفا کد رو درست بررسی کنید ، اسم تابع استفاده شده بیانگر نحوه عملکرد تابع هست ، کدی که من نوشتم بررسی میکنه اگر شئ ساخته نشده بود پیغام رو نمایش میده ، خوب تو کد شما شئ ساخته شده پس پیغام نمایش داده نمیشه !

برای آزاد کردن شئ مورد نظر هم از تابع FreeAndNil استفاده کن .

shedayat
پنج شنبه 15 تیر 1391, 23:39 عصر
بازم ممنون. ولی یه بار خودتون این کد رو امتحان کنید.
به جان خودم من همین کد رو اصلا کپی پیست می کنم ولی باور کن جواب نمیده.(چه با اضافه کردن اون خط و چه با اضافه نکردنش!!!). در هر دو صورت شرط داخل if برقرار نمی شه.
var
A: TButton;
begin
if IsBadReadPtr(A, sizeof(Pointer)) then
ShowMessage('');
end;

Felony
جمعه 16 تیر 1391, 00:24 صبح
یعنی کد بالا که گذاشتید پیغام رو نشون نمیده ؟ ویندوز 32 بیت یا 64 بیت ؟

فعلا راه حلی که به نظم میرسه استفاده از همون Assigned هست ، قبل از بررسی شئ اون رو nil کن یعنی :

var
A: TButton;
begin
A:= nil;
if Assigned(A) then
ShowMessage('');
end;

shedayat
جمعه 16 تیر 1391, 00:34 صبح
یعنی کد بالا که گذاشتید پیغام رو نشون نمیده ؟ ویندوز 32 بیت یا 64 بیت ؟
نه!!! ویندوز من 32 بیتی هست.

فعلا راه حلی که به نظم میرسه استفاده از همون Assigned هست ، قبل از بررسی شئ اون رو nil کن یعنی :

var
A: TButton;
begin
A:= nil;
if Assigned(A) then
ShowMessage('');
end;
این کد رو هم امتحان کردم. ولی بی نتیجه بود. :(
ممنون از اینکه وقت گذاشتی و پاسخ سوالام رو دادی.

Felony
جمعه 16 تیر 1391, 04:56 صبح
بی نتیجه بود یعنی چی ؟! اون کد نباید پیغامی رو نشون بده ، بعد از ساخت شئ پیغام رو نمایش میده ، برای آزاد کردن شئ هم از FreeAndNil استفاده کن .

shedayat
جمعه 16 تیر 1391, 09:52 صبح
بی نتیجه بود یعنی چی ؟!
یعنی اینکه اون کد هم تو حالتی که شی رو ایجاد می کنم و هم زمانی که ایجادش نمی کنم پیغامی نمایش داده نمی شه.
یعنی:
هم توی این حالت:
var
A: TButton;
begin
a:=TButton.Create(nil);
A:= nil;
if Assigned(A) then
ShowMessage('');
end;
و هم این حالت:
var
A: TButton;
begin
A:= nil;
if Assigned(A) then
ShowMessage('');
end;

Felony
جمعه 16 تیر 1391, 10:15 صبح
ای بابا ! خوب نبایدم نشون بده ، در هر دو کد برداشتی مقدار اشاره گر رو Nil کردی ، یکم دقت کن ...

var
A: TButton;
begin
if Assigned(A) then
ShowMessage('شئ ساخته نشده ولی اشاره گر آن معتبر است');
/// //////////////////////////
A := nil;
if Assigned(A) then
ShowMessage('اشاره گر شئ نامعتبر است ، پس پیغام نماش داده نمیشود');
/// //////////////////////////
A := TButton.Create(nil);
if Assigned(A) then
ShowMessage
('شئ ساخته شده و اشاره گر آن معتبر است و پیغام نمایش داده میشود');
/// //////////////////////////
FreeAndNil(A);
if Assigned(A) then
ShowMessage('شئ آزاد شده و اشاره گر آن نامعتبر است پس پیغام نمایش داده نمیشود');
end;

shedayat
جمعه 16 تیر 1391, 10:39 صبح
خیلی ممنون از اینکه وقت می زارید و پاسخ می دین. بالاخره متوجه که مشکل کارم از کجا بود. :D
پس با این توضیحی که شما زحمت کشیدید چطور می شه کدی نوشت که اگه به فرض یه دکمه ساخته شده بوده دیگه ساخته نشه و اگه ساخته نشده بود، ساخته بشه. :متفکر:
ممنون.

Felony
جمعه 16 تیر 1391, 12:22 عصر
شئ رو در بخش Private فرمتون تعریف کنید :

type
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
A: TButton;
public
{ Public declarations }
end;

در رویداد OnCreate یا ... فرم برنامتون ابتدا اشاره گر مرتبط رو nil کنید :

procedure TForm1.FormCreate(Sender: TObject);
begin
A := nil;
end;

در آخر برای بررسی شئ :

if Assigned(A) then
ShowMessage('شئ ساخته شده و اشاره گر آن معتبر است و پیغام نمایش داده میشود')
else
A := TButton.Create(nil);

یادتون باشه برای آزاد سازیش از FreeAndNil استفاده کنید .

shedayat
جمعه 16 تیر 1391, 12:31 عصر
دستت درد نکنه. دیگه مشکلم به طور کامل حل شد. از اینکه وقت گذاشتی و به سوالاتم جواب دادی متشکرم.