Solved

Object.free not really freeing up the object

Posted on 2007-03-23
21
473 Views
Last Modified: 2013-11-22
Starting from this question: http://www.experts-exchange.com/Programming/Languages/Pascal/Delphi/Q_22465181.html
I found something weird (for me at least):
freeing an object does not release all its memory right away.

so lets take this example to play with:

function objExists(obj:TObject):boolean;
begin
  try
    if obj.classtype=nil then;// just access a member. should through an AV if the obj does not exist
    result:=true;
  except
    result:=false;
  end;
end;

procedure TForm1.FormCreate(Sender: TObject);
var x:TObject;
begin
  if objexists(x) then
    showmessage('function failed');
  x:=tobject.create;
  if not objexists(x) then
    showmessage('function failed');
  x.free;
  if objexists(x) then
    showmessage('function failed');
end;

you will receive 2 failures: 1st if and 3rd if.

now, the interesting part is this: x is not initialized, which means it has some random value. in our case it points to tform1. (at least on my machine). how I know that? simple: I put a breakpoint in the objexist function on the if statement and put in watch: obj=form1 and returns true. (of course, I first checked the classtype and saq tofrm1 and that's how I got the diea :) )

so ... even if the 1st if statement is a little curious, I'm not really interested in it since x is not initialized and anything can happen.
however, I am interested to know why the 3rd if statement is not working correctly.
and afterwards: how can we fix that? (it so happens I used eurikalog yesterday after I got a "no more memroy available" kind of error and it tracked down under 1 MB od memory leaks, most of them in classes.pas, sysutils.pas, etc. so this is why I am even more intereested in understanding this memory management stuff and why can't I rely on the fact that after I freed an object it is really freed)

thanks
0
Comment
Question by:ciuly
  • 9
  • 6
  • 5
  • +1
21 Comments
 
LVL 21

Assisted Solution

by:ziolko
ziolko earned 200 total points
ID: 18778661
maybe i'm boring but thats why i always use Assigned() and FreeAndNil() :)
dunno when object previously allocated by object is "really" released i suppose
that when it become used by some other object, but its matter of definition of "really freed" :)

so i use Assigned() to see if object is not nil and FreeAndNil() to free memory and assign nil to variable
in same time.

I use FastMM, no memory leaks reported.

ziolko.
0
 
LVL 28

Author Comment

by:ciuly
ID: 18778743
well, that is good practice, but consider the case of starting to work on an existing project and the previous developer did not use freeandnil (nor assigned) and there will be one specific line where he creates a control with a nil owner, and forgets to free it. you will use that exact control with assigned and ... it will not give you the correct information. I hvae such a project where I synamically create a series of buttons on a listview which are freed when the items are deleted. (so yes, in this case I didn't forget :P, but I just want to outline that it's not so rare such scenario)

so basically, the key use is setting the object to nil, eitehr explicitly, or by use of some function like freeandnil. but I am waiting for some good explanations on "why not my way?" problem :)
0
 
LVL 10

Expert Comment

by:dinilud
ID: 18778790
I think the object is freeing and relasing memory . But The object pointer is not setting nil.  
    So i think, if we try  to access that object again, program will assume the object is there because that pointer is not nil. So we get that random number as the instend size. I am also not sure is my concept is currect or not.

I am also eagerly looking for answer
0
 
LVL 21

Expert Comment

by:ziolko
ID: 18778881
ciuly in case of inherited project, i would find this guy and... shake him a little bit:)
other trick (but only trick strongly NOT recommended) is to dump objects to TObjectList
which will destroy everything with it:)

dinilud you're right when object reference is not nil and you will access
program will treat it like existing object and will read memory where objects was
so until memory won't be over-written there's chance you can get some
values. when object is released memory bits it allocated are not wiped clear.

ziolko.
0
 
LVL 10

Expert Comment

by:dinilud
ID: 18780002
first try this
=========

procedure TForm1.Button1Click(Sender: TObject);
var X:Pointer;
    a:Char;
begin
  X:=@a;
  ShowMessage(BoolToStr(True,TForm1(X).Visible));
//  TForm1(X).Visible:=False;
end;


second try this
===========
procedure TForm1.Button1Click(Sender: TObject);
var X:Pointer;
    a:Char;
begin
  X:=@a;
  ShowMessage(BoolToStr(True,TForm1(X).Visible));
  TForm1(X).Visible:=False;
end;
0
 
LVL 21

Expert Comment

by:ziolko
ID: 18780135
BoolToStr() converts boolean to string in both your samples
you try convert true  to string so only two possible
results are 'TRUE' or '-1'

ziolko.
0
 
LVL 21

Expert Comment

by:ziolko
ID: 18780399
var X:Pointer;
    a:Char;
begin
  X:=@a;
  TForm1(X)

this way when you access any property of form you will read random data, or get access violation error

ziolko.
0
 
LVL 21

Expert Comment

by:ziolko
ID: 18780434
open system.pas and look how TObject's InitInstance() or InstanceSize() are written
reference to object is not simple pointer

ziolko.
0
 
LVL 10

Expert Comment

by:dinilud
ID: 18784558
We can access property.
It is our responsibility to inform compilier which type of pointer it is.

type PForm2=^TForm2;

procedure TForm1.Button1Click(Sender: TObject);
var x:Pointer;
begin
  x:=@Form2;
  PForm2(x).Visible:=True;
end;
0
 
LVL 21

Expert Comment

by:ziolko
ID: 18784901
yup but:
 var X:Pointer;
    a:Char;
begin
  X:=@a;
is significantly different than:
var x:Pointer;
begin
  x:=@Form2;


ziolko.
0
What Is Threat Intelligence?

Threat intelligence is often discussed, but rarely understood. Starting with a precise definition, along with clear business goals, is essential.

 
LVL 10

Expert Comment

by:dinilud
ID: 18784926
Sir

i know in that examples are wrong.
This i wrote this to point out, where is the error. thats all
0
 
LVL 21

Expert Comment

by:ziolko
ID: 18784951
well it's not error it's designed behaviour.

basically object is pointer to memory where object's instance "begin"
something like starting point, so for example when you try access some property
you have to jump Offset bytes from this starting point, there you'll find
property table, next you have to find position of property in table (which
means another jump by x bytes) once you're in right position in table
you find another pointer where you have to jump to read property value,
so as you can see if you have wrong starting point you'll be jumping
over memory into random places.

so when you have
var a, b: TSomeObject;

a := TSomeObject.Create;
b :=a ;
you can access to TSomeObject's properties
using both a or b because their pointing to same starting point
and they are both of the same type so all offest's are the same
also thats why once you destroy b and you'll try access a's properties
you'll get aceess violation error or if you're lucky random values

ziolko.

0
 
LVL 28

Author Comment

by:ciuly
ID: 18784958
guys, guys, we're getting off-track here.

let's not forget what started this: an object is freed via the free method call but the memory is not fully released. I for example have a project right now in which I iterate through 8000 files and create/destroy a lot of objects. however I got an eoutofmemory exception so if there is a memory leak somewhere or something that to do in order to force releasing the memory, or whatever, I at least *need* to know and understand what is going on there (especially because for every single file I create a bunch of strings, dynamic arrays and variants, not to mention at least one xml document). so i really have to understand what is going on there (since it seems I was on the wrong track thinking the memory was actually released and so the error was from somewhere else: now it can be that the error si exactly because of this).
There are a few experts around here that have such knowledge and I'm waiting for their input, though I rarely seen them after the new interface went online (I haven't got in too much eitehr because of it, just to keep my monthly minimum points up)
maybe I'll buzz them up, but I'll wait another few days just in case.

if you have time and will, I don't mind if you search for some other references on teh subject and post them ;) but let's keep it on the subject.

thanks
0
 
LVL 21

Expert Comment

by:ziolko
ID: 18784975
ciuly,  agree i haven't seen some of the "top dogs" lately.

if it comes to memory leaks, did you try this: http://sourceforge.net/projects/fastmm/
i use it, pretty cool tool. i have written network server working 24/7,  with lots of
allocating/deallocating memory, fastmm helped me find places where i forgot to free some
objets:) but know it's 9 months since app was last restarted and no problems with memory

ziolko
0
 
LVL 28

Author Comment

by:ciuly
ID: 18784999
no, but I did download it when you first mention it (in your first post). right now I jsut have to find a workaround to my problem (which is pagination, meaning that only a handfull of items will be loaded in memroy, rest will be persisted on disk). We should have had teh release a few days back, but this memory issue just came up (I should do stress testing a little more often) and the client said I need to fix it by monday so for now, just a small "hack", after that I'll check this fastmm and see what it can do for me. I did use eurekalog and memcheck and pasanalyzer but I didn't get too much info. I found a palce where I forgot to free an object (ups :D ) while commenting out some pieces of code to track the basterd down, but I still have a big memory usage so there must be soemthing more. from code, I can't see anything else (spent some hours doing method by method check) so I am thinking it could be because of tobject not freeing up all strings, variants, dynamic arrays and who knows what else at the moment I call the free method (the actuall freeing should be done when CleanupInstance is called ... but I can't figure out when that is done so ... that is one of the reasons I turned to the "old dogs" :) )
0
 
LVL 21

Expert Comment

by:ziolko
ID: 18787652
i haven't got problems with tobject freeing string but, if you use TList with records which contains string fileds you have to call SetLength(astring, 0) before disposing records pointer on list. this is something that i'll remember for ever:)

ziolko.
0
 
LVL 28

Author Comment

by:ciuly
ID: 18787662
hm.... I rarely use records as I usually also need to persist the date and to save myself time I've made some basic xml persistance framework based on objects to I use the same object for everything: storing in list, displaying the data and saving/loading to/from disk.
however your suggestion is an interesting thing to test for. hope I won't forget to do it next week :D
0
 
LVL 10

Expert Comment

by:dinilud
ID: 18790938
I HAD NO PROBLEM WHILE RELEASING OBJECT.

==========================================

procedure FreeAndNil(var Obj);
var
  Temp: TObject;
begin
  Temp := TObject(Obj);
  Pointer(Obj) := nil;
  Temp.Free;
end;

THIS IS THE DEFINITION OF FreeAndNil() PROCEDURE IN SysUtils.
I BELIEVE THE ANSWER OF YOUR QUESTION IS THERE IN THIS DEFINITION.
0
 
LVL 28

Author Comment

by:ciuly
ID: 18791377
you believe wrong. probably because you didn't understand the question and the rest of my posts. nil-ing a reference is out of the scope of this trhead. that is indeed a **SOLUTION** to the problem but it's not an **EXPLANATION** of it. anyway, let's move on and wait for the people who actually know the low level details of the problem to explain it.
0
 
LVL 6

Accepted Solution

by:
House_of_Dexter earned 300 total points
ID: 18796620
k...lets get back to the basics...

First...Objects are nothing more than fancy pointers that the compiler has more knowledge about.

When we are dealing with pointers we are dealing with a memory location.

In your example.

  if objexists(x) then//<---invalid address, we are not pointing at anything...
    showmessage('function failed');
  x:=tobject.create;//<--good address pointing at object
  if not objexists(x) then//<--no problem...good address good object
    showmessage('function failed');
  x.free;//<---freed object...x still points to the old memory location...which has no object
  if objexists(x) then{<---can't call on x...it's not pointing to a valid address(you have no idea what windows maybe poiting to now at that address}
    showmessage('function failed');


couple things of note...x is local scope variable...when it falls out of scope you will lose all reference to it(which is a potential memory leak unless trap it in a try finally block and free it)...or unless you place it in some type of list...


Here are some rules...Local Scope object should always be in a try finally...or if it's in a List...you should have your clean up code make sure that the List is cleared correctly...usually in a Destructor...and specific code that may delete it out of the list...or if the object is referenced in another object...you should make sure when you free it...that you nil it...

procedure MyProc;
//local scope example
var
  a_MyObject: TObject;
begin
  a_MyObject := TObject.Create;
  try
    //work on my a_MyObject
  finally
    a_MyObject.Free//know need to point to nil...going to fall out of scope...
  end;
end;

//some typical creation and destruciton of objects...
procedure TMyObject.Initialize;
begin
  if Not Assigned(FObj) then
    FObj := TMyObject.Create;
end;

procedure TMyObject.DeInitialize;
begin
  FObj.Free;
  FObj := nil;
  //could use FreeAndNil(FObj);
end;


0
 
LVL 28

Author Comment

by:ciuly
ID: 18839330
well ... I'll guess I'll have to settle with what I received.
thanks for the help guys
0

Featured Post

How to improve team productivity

Quip adds documents, spreadsheets, and tasklists to your Slack experience
- Elevate ideas to Quip docs
- Share Quip docs in Slack
- Get notified of changes to your docs
- Available on iOS/Android/Desktop/Web
- Online/Offline

Join & Write a Comment

Suggested Solutions

Title # Comments Views Activity
How to convert wav to mp3 in delphi 9 138
IExtractImage Delphi 14 168
Delphi inherited method 6 42
Dynamically Created Query 3 13
Objective: - This article will help user in how to convert their numeric value become words. How to use 1. You can copy this code in your Unit as function 2. than you can perform your function by type this code The Code   (CODE) The Im…
Introduction Raise your hands if you were as upset with FireMonkey as I was when I discovered that there was no TListview.  I use TListView in almost all of my applications I've written, and I was not going to compromise by resorting to TStringGrid…
Internet Business Fax to Email Made Easy - With eFax Corporate (http://www.enterprise.efax.com), you'll receive a dedicated online fax number, which is used the same way as a typical analog fax number. You'll receive secure faxes in your email, fr…
This video shows how to remove a single email address from the Outlook 2010 Auto Suggestion memory. NOTE: For Outlook 2016 and 2013 perform the exact same steps. Open a new email: Click the New email button in Outlook. Start typing the address: …

744 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

12 Experts available now in Live!

Get 1:1 Help Now