Article View: borland.public.cppbuilder.database.ado
Article #717Re: Problem on memory leak with TADOQuery
From: Sara T.
Date: Mon, 01 Aug 2005 05:30
Date: Mon, 01 Aug 2005 05:30
182 lines
7807 bytes
7807 bytes
Somebody fixed somecode in ADODB.pas, why Borland does not provide any hot
fix to solve?
Sara T.
"AlexB" <b.a.v@inbox.ru> wrote in message
news:42e705cf$1@newsgroups.borland.com...
> Sara T. wrote:
>> I have something to create and destroy this object (TADOQuery) a lot
>> of times, I found TADOQuery does not release the
>> memory and eats memory until the machine becomes out of memory.
>> I'm using an simple ADOQuery with:
> >
>> AdoQuery1.Close; AdoQuery1.Sql.Clear;
>> AdoQuery1.SQL.Add('select * from myTable'); AdoQuery1.Open;
>>
>> Every call I lose memory. I found the same question in Google but
>> nobody answers.
>
> Some month ago:
> =========================================
> D7, ADODB unit.
> we use Jedi or memcheck to track if memory is lost or not. This tools
> say that there is a problem in adodb unit when the tadoquery is freed.
> So we checked the source code of the vcl and made some modifications:
>
> destructor TADOCommand.Destroy;
> begin
> // we modified like this ==>
> Connection := nil;
> FCommandObject := nil;
> FreeAndNil(FParameters);
> // we modified : end
> inherited Destroy;
>
> { // this is the original source code
> Connection := nil;
> FCommandObject := nil;
> FreeAndNil(FParameters);}
> end;
>
> destructor TADOQuery.Destroy;
> begin
> // we modified like this ==>
> FreeAndNil(FSQL);
> // we modified : end
> inherited Destroy;
>
> // FreeAndNil(FSQL); // original source code
> end;
>
> Now: no more memory problem.
> Do you think we can used our modifications? Do you agree with that?
> ---
> These fixes are already present in D7 Update 1.
> ---
> I've just passed the Delphi 7 update 1.
> The VCL has not changed, the problem still exists.
> -------- End of quotation -----------------------
> I.e. original VCL src calls "inherited Destroy;" before some other
> statements. It's not so good practice but pascal allows it and in theory
> no leaks present here... Try to patch ADOdb.pas as described above.
> =================================================
> QualityCentral #8837
>
> I guess "memory leak" needs no further explanation ;) See steps how to
> reproduce... I've traced the memory leak down to
> WideStringField.GetAsVariant() in DB.pas. See workaround for possible fix.
>
> (Tested with English D7 Build 8.1)
> 1. Create a MS-Access 2000 MDB containing a table "Table1" with a string
> column named "Column1". Add a few records to that table (actual column
> text doesn't matter)
> 2. Create a new Delphi application. Drop a TADOConnection and a
> TADOTable on the form and connect them to "Table1" in the Access database
> 3. Drop a TButton and add the following lines to it's OnClick event
> handler, which basically just accesses the first two rows of the table
> alternatingly and reads them into a variable type Variant:
>
> procedure TForm1.Button1Click(Sender: TObject);
> var
> v: Variant;
> begin
> try
> ADOTable1.Open;
> repeat // forever
> v := ADOTable1.FieldByName('Column1').Value;
> ADOTable1.Next;
> v := ADOTable1.FieldByName('Column1').Value;
> ADOTable1.Prior;
> until False;
> finally
> ADOTable1.Close;
> end;
> end;
>
> 4. Compile the application and run it (outside Delphi). Watch memory
> consumption in the Windows task manager.
>
> memory consumption increased endlessly before the fix (I interrupted the
> process at 100 MB) , and after the fix, it never goes over a certain
> limit (10 MB in my test app). I've tested it with MemProof. For both
> "Live Pointers" and "Virtual Memory", the peak size keeps increasing
> permanently.
>
> Workaround:
>
> Instead of using
> DataSet.FieldValues['myfield'] or
> DataSet.FieldByName('myfield').Value,
> use one of the following workarounds:
>
> 1) TWideStringField(DataSet.FieldValues['myfield']).Value, which
> retrieves the field value as WideString and not as Variant.
>
> 2) Use the following function
> GetWideString(DataSet.FieldByName('myfield') as TWideStringField) to
> retrieve the value as Variant without leaking memory.
>
> function GetWideString(field: TWideStringField): Variant;
> var
> S: WideString;
> begin
> if field.DataSet.GetFieldData(field, @S, False)
> then Result := S;
> else Result := Null;
> end;
>
> IMHO 2) is also a possible fix for Delphi's VCL.
> TWideStringField.GetAsVariant() and my workaround function above differ
> only in 2 points, both of which cause a memory leak:
> - S is declared as PWideChar instead of WideString
> - Instead of simply using "Result := S", the following code is used.
> TVarData(Result).VOleStr := PWideChar(S);
> TVarData(Result).VType := varOleStr;
>
> I don't understand Delphi's memory management of WideStrings well enough
> to tell where exactly the memory leaks come from, but this workaround
> seems to fix them.
> ========================================
> Does anyone know about memory leak issue in TADOQuery? I've search in
> Google and Google Groups and I found only very little info about this,
> although the problem is spot on. SysString is not released after closing
> and freeing ADO Query. I found one workaround from QualityCentral #8837
> but there's another that I couldn't fix. The code is very simple:
>
> adoQuery := TADOQuery.Create(nil);
> adoQuery.Connection := adoConnection;
> adoQuery.Prepared := True;
> adoQuery.SQL.Add('SELECT Title, Description ');
> adoQuery.SQL.Add('FROM User WHERE Id = ' + IntToStr(Self.FUserId));
> adoQuery.Open();
> adoQuery.SQL.Clear(); // <-Clear before Close??? (AlexB)
> adoQuery.Close();
> adoQuery.Free();
>
> On MemProof this will yield SysString not freed resources from deep
> inside TCustomADODataSet. The last three entries on the stack is like
> this:
>
> system.pas WStrFromPWCharLen
> variants.pas VarFromWStr
> adodb.pas TCustomADODataSet::InternalInitFieldDefs
>
> If I put this snippet in an iteration the number of SysString unreleased
> will go up. Does anyone know any workaround/resolution for this issue?
> ------------------
> (without answer...)
> ==================================
> Another tips:
> ==================================
> SetProcessWorkingSetSize(GetCurrentProcess(), DWORD(-1), DWORD(-1));
>
> after test. This will trim working memory set. If this helps, there is
> no memory leak, if not - use MemCheck or other tool to find a leak.
> ==================================
> Get TBetterADODataSet (free) and test again. It is said to fix some
> problems in the original.
> =================================
>
> Good lack ...
> Alex.
Technical Details
Message-ID:
<42edb3ae@newsgroups.borland.com>Path:
arc1-ca.pugleaf.net!g2news1.google.com!news2.google.com!proxad.net!213.200.89.82.MISMATCH!tiscali!newsfeed1.ip.tiscali.net!newsfeed00.sul.t-online.de!newsfeed01.sul.t-online.de!t-online.de!newsgroups.borland.com!not-for-mailReferences:
<42e4d1b3$1@newsgroups.borland.com> <42e62634$1@newsgroups.borland.com> <42e64264$1@newsgroups.borland.com> <42e705cf$1@newsgroups.borland.com>Show Full Headers
Complete Article Headers
X-Google-Thread: 10698b,5b03d9688e33bc12 X-Google-Attributes: gid10698b,public X-Google-Language: ENGLISH,ASCII-7-bit From: "Sara T." <sarana@thaiquest.com> Newsgroups: borland.public.cppbuilder.database.ado References: <42e4d1b3$1@newsgroups.borland.com> <42e62634$1@newsgroups.borland.com> <42e64264$1@newsgroups.borland.com> <42e705cf$1@newsgroups.borland.com> Subject: Re: Problem on memory leak with TADOQuery Date: Mon, 1 Aug 2005 12:30:43 +0700 Lines: 184 X-Priority: 3 X-MSMail-Priority: Normal X-Newsreader: Microsoft Outlook Express 6.00.2900.2180 X-MimeOLE: Produced By Microsoft MimeOLE V6.00.2900.2180 X-RFC2646: Format=Flowed; Response NNTP-Posting-Host: 202.142.216.253 Message-ID: <42edb3ae@newsgroups.borland.com> X-Trace: newsgroups.borland.com 1122874286 202.142.216.253 (31 Jul 2005 22:31:26 -0700) Path: arc1-ca.pugleaf.net!g2news1.google.com!news2.google.com!proxad.net!213.200.89.82.MISMATCH!tiscali!newsfeed1.ip.tiscali.net!newsfeed00.sul.t-online.de!newsfeed01.sul.t-online.de!t-online.de!newsgroups.borland.com!not-for-mail