I connect to a SAP server via SAP Logon Control TLB (which eats about 25MB of mem at first start!!) and then query some data. Each call requires ~200 kB. Because I don't want to reconnect every time, I store the connection and pass it to the SAP Function object every time I need it (it seems the object is copied, because this proc also costs about 6MB).
After I'm done querying, I free the object but the memory usage is not going down. Why?
Therefore, if I let the program run for about 4 hours, my memory is full and the PC crashes.
The code (simplified):
connection.pas
(creates the connection):
SAPLogonCtrl : TSAPLogonControl;
constructor TCon.Create(usr, pswd, sys, appserv, sysnum, clnt);
begin
inherited Create;
SAPLogonCtrl := TSAPLogonControl.Create(nil);
with SAPLogonCtrl do begin
User := usr;
Password := pswd;
...
Client := clnt;
end;
FConnection := SAPLogonCtrl.NewConnection;
FConnection.Logon(0, true); //<------------- this needs ~25MB
end;
main.pas
:
...
procedure TMain.Query;
var
theQuery : TSomeQuery;
begin
theQuery := TSomeQuery.Create;
theQuery.Data1 := 'something gets here';
theQuery.Data2 := 'here too';
theQuery.Call; // <------------------------ this needs about ~100kB
...
theQuery.Free; // <------------------------ nothing happens here, no mem freed!
end;
...
someQuery.pas
(creates the object and calls the query):
var
mySAPFunction: TSapFunctions;
mySAPQuery: Variant;
...
procedure Call;
begin
mySAPFunction := TSAPFunctions.Create;
mySAPFunction.Connection := FConnection; // <---- connection is passed (copied? costs about 5MB) from connection.pas
mySAPFunction.RemoveAll; // removes prevous added interfaces
mySAPQuery := mySAPFunction.Add('interface here');
mySAPQuery.Call;
...
// return the result
end;
I hope this is understandable and that someone can help me because with this memory leak my program is practically unusable :(
Thanks in advance, Eike.
You can force to release a variant interface instance by setting it to nil:
procedure Call;
begin
mySAPFunction := TSAPFunctions.Create;
mySAPFunction.Connection := FConnection; // <---- connection is passed (copied? costs about 5MB) from connection.pas
mySAPFunction.RemoveAll; // removes prevous added interfaces
mySAPQuery := mySAPFunction.Add('interface here');
mySAPQuery.Call;
mySAPQuery := null; // will release the memory
end;
In fact, I think mySAPQuery should be made local to your Call procedure: in this case, the mySapQuery := null
statement will be made by the compiler.