UnicodeString Memory Leak in DataSet

delphi package - automated exception handling
Post Reply
AlbertoWP
Posts: 5
Joined: Wed Jun 28, 2017 11:22 am

UnicodeString Memory Leak in DataSet

Post by AlbertoWP »

Hello,

I´m using Embarcadero RAD Studio XE7. My problem is that I have a memory dataset which contains many fields. Some of them are string type and I have a record like this:

For example:

Code: Select all

kbmMyDataSet: TKbmMemTable;
kbmMyDataSetIntegerVar1: TIntegerField;
kbmMyDataSetIntegerVar2: TIntegerField;
kbmMyDataSetStringVar1: TStringField;
kbmMyDataSetStringVar2: TStringField;

RMyRec=record
    IntegerVar1:Integer;
    IntegerVar2:Integer;
    StringVar1:string;
    StringVar2:string;  
  end;
I have created the variable vMyRec with type RMyRec (record) and I assign their integers and strings from the dataset.

Code: Select all

 procedure RellenarInfo;
 begin
  vMyRec.IntegerVar1:=kbmMyDataSetIntegerVar1.Value;
  vMyRec.IntegerVar2:=kbmMyDataSetIntegerVar2.Value;
  vMyRec.StringVar1:=kbmMyDataSetStringVar1.AsString; <--- memory leak,  kbmMyDataSetStringVar1.AsString='PLATA' and it assigns properly to vMyRec.StringVar1
  vMyRec.StringVar2:=kbmMyDataSetStringVar2.AsString;
 end;
When I close the application, it throws a UnicodeString memory leak.

The stacktrace says:

madExceptDbg - GetMemCallBack
System - @GetMem
System - @NewUnicodeString
System - @UStrFromPWCharLen
System - InternalUStrFromPCharLen
Data.DB - TStringField.GetAsString;
UForm1 - TForm1.RellenarInfo; // my procedure

I have found this same problem with a query (FibPlus library)

Anyone can help me with this problem?

Best rewards.
Alberto
madshi
Site Admin
Posts: 10754
Joined: Sun Mar 21, 2004 5:25 pm

Re: UnicodeString Memory Leak in DataSet

Post by madshi »

What is "vMyRec"? Is it a global variable? Which type? Is it type RMyRec? Or a pointer type like "^RMyRec"?
AlbertoWP
Posts: 5
Joined: Wed Jun 28, 2017 11:22 am

Re: UnicodeString Memory Leak in DataSet

Post by AlbertoWP »

madshi wrote:What is "vMyRec"? Is it a global variable? Which type? Is it type RMyRec? Or a pointer type like "^RMyRec"?
I did the example very fast, sorry.

vMyRec is a variable from the main class (TForm1) and its type is RMyRec (not a pointer).
madshi
Site Admin
Posts: 10754
Joined: Sun Mar 21, 2004 5:25 pm

Re: UnicodeString Memory Leak in DataSet

Post by madshi »

And the main form is properly destroyed? If so, during TForm1.Destroy "vMyRec" should automatically be cleaned up and if RMyRec is not a pointer, then that cleanup should include RMyRec.StringVar1/2.

So what does this mean? It could be a bug in the leak reporting. Or it could be that the "AsString" method returns a string which has a too high reference counter. After all, TForm1.Destroy will only decrement the RMyRec.StringVar1/2 by 1, so if the reference counter of that string is higher than 1, it will not be cleared. However, usually System string units are clean, so I wouldn't expect a bug in "InternalUStrFromPCharLen". You could of course double check TStringField.GetAsString to make sure the code is clean.
AlbertoWP
Posts: 5
Joined: Wed Jun 28, 2017 11:22 am

Re: UnicodeString Memory Leak in DataSet

Post by AlbertoWP »

I have changed the code to assign strings:
- I tested using "Value" instead of "AsString" (same result)
- Changing type from dataset variable from "TStringField" to "TWideStringField" (same result)

I think the problem could be in conversion between UnicodeStrings and AnsiStrings. Our project is a migration from Delphi 2007 to XE7.

Its very difficult to find out where the error is because there are many code lines in the project. :o
madshi
Site Admin
Posts: 10754
Joined: Sun Mar 21, 2004 5:25 pm

Re: UnicodeString Memory Leak in DataSet

Post by madshi »

It *could* be a bug in the leak reporting. Can you reproduce this problem in a simple test project?
AlbertoWP
Posts: 5
Joined: Wed Jun 28, 2017 11:22 am

Re: UnicodeString Memory Leak in DataSet

Post by AlbertoWP »

I changed the line that produces the memory leak for a constant value and the problem persist:

Code: Select all

 procedure RellenarInfo;
 begin
  vMyRec.IntegerVar1:=kbmMyDataSetIntegerVar1.Value;
  vMyRec.IntegerVar2:=kbmMyDataSetIntegerVar2.Value;
  vMyRec.StringVar1:='1234'; <--- memory leak
  vMyRec.StringVar2:=kbmMyDataSetStringVar2.AsString;
 end;
Until now I don´t get to reproduce the error in a simple project...
madshi
Site Admin
Posts: 10754
Joined: Sun Mar 21, 2004 5:25 pm

Re: UnicodeString Memory Leak in DataSet

Post by madshi »

Is that the only leak you're getting? Or are there more? I'm wondering if maybe the form gets created twice but freed only once, or something like that? But if that would be the case, you should see a LOAD of leaks reported.

Another option is that maybe some part of your code overwrites the vMyRec record with zeroes, which would prevent TForm1.Destroy from properly cleaning the string.

Does this leak report happen every time you run the application? If so, you could set a breakpoint in TForm1.Destroy and check if vMyRec.StringVar is still set, and you can also check the reference count (it's stored in memory before the string characters, so you can access it by using pointer logic).
AlbertoWP
Posts: 5
Joined: Wed Jun 28, 2017 11:22 am

Re: UnicodeString Memory Leak in DataSet

Post by AlbertoWP »

Is that the only leak you're getting? Or are there more? I'm wondering if maybe the form gets created twice but freed only once, or something like that? But if that would be the case, you should see a LOAD of leaks reported.
It is not the unique leak. There are many more leaks with strings in another classes even memory leak in a private string variable. I was looking the creation and destruction from the form and other classes but I saw it is called each one once.
Another option is that maybe some part of your code overwrites the vMyRec record with zeroes, which would prevent TForm1.Destroy from properly cleaning the string.
The record is used several times while the form is active. I saw in the Destroy that the record had valid values (last values from use record) and I put the strings to empty strings in the destroy but without effect.
Does this leak report happen every time you run the application? If so, you could set a breakpoint in TForm1.Destroy and check if vMyRec.StringVar is still set,
I can reproduce the problem when I enter in a form after open previous several forms.
and you can also check the reference count (it's stored in memory before the string characters, so you can access it by using pointer logic).
How can I exactly see the reference count from a string using a pointer?
madshi
Site Admin
Posts: 10754
Joined: Sun Mar 21, 2004 5:25 pm

Re: UnicodeString Memory Leak in DataSet

Post by madshi »

IIRC, there are 2 DWORDs stored right in front of the string data. So you could check "(PULONG(vMyRec.StringVar) - 1)^" and "(PULONG(vMyRec.StringVar) - 2)^". One should be the string length, the other the reference counter. Or maybe it's 3 DWORDs? You can also check "(PULONG(vMyRec.StringVar) - 3)^". This PULONG arithmetic may only work in newer Delphi versions, I'm not sure. If it fails, you'll have to use some more complex syntax to apply the pointer arithmetic.
Post Reply