ghkweon / dwscript

Automatically exported from code.google.com/p/dwscript
0 stars 0 forks source link

[Code Suggestion] Leak of TProgramInfo.RegisterExternalObject #295

Closed GoogleCodeExporter closed 8 years ago

GoogleCodeExporter commented 8 years ago
my2cts,

because I can't change neither extend classes I export to the scripts (to add 
the ScriptObj field suggested in demos), I searched and found a workaround for 
the leak of RegisterExternalObject:

I use a TDictionnary<TObject, Variant> and this method:

function TDW_Unit.GetScriptObjFromExternal(info: TProgramInfo; AObject: 
TObject): Variant;
begin
  Result := Unassigned;
  if not FScriptObjInstances.TryGetValue(AObject, Result) then
  begin
    Result := info.RegisterExternalObject(AObject, False, False);
    FScriptObjInstances.Add(AObject, Result);
    FExternalInstances.Add(Result, AObject);
  end;
end;

and a generic Destroy event for all of my classes:

procedure TDW_Unit.HandleDestroy(info: TProgramInfo; ExternalObject: TObject);
var
  v: Variant;
begin
  if FScriptObjInstances.TryGetValue(ExternalObject, v) then
  begin
    FExternalInstances.Remove(v);
    FScriptObjInstances.Remove(ExternalObject);
  end;
  ExternalObject.Free;
end;

So far so good. The only problem I see for now is that only objets created 
trough the script are really removed from the list.
Objects that were already created (such as TObjectList.Items proprety) before 
the execution of the script cannot be removed.
I didn't find a way to clear the list at the end of the execution.

I know this solution is not thread safe (in my case I don't care) but think 
it's possible to make it thread safe at low cost.

Original issue reported on code.google.com by tetra...@gmail.com on 4 Sep 2012 at 8:31

GoogleCodeExporter commented 8 years ago
The simplest solution is to add reference-counting to your external classes, 
this should also work with shared resources/object.

You can either just add a "RefCount" field to your classes, or wrap them in a 
very simple class that would take care of releasing them (feel free to use 
dwsUtils's TRefCountedObject for that).

A variantof refcounting based on your above snippet is to to allow the same 
object to be added multiple times in your FScriptObjInstances (using a list 
rather than a dictionnary), and only perform the "ExternalObject.Free" when it 
is no longer present (ie. no longer referenced by any script)

Original comment by zar...@gmail.com on 4 Sep 2012 at 9:10

GoogleCodeExporter commented 8 years ago
Thanks a lot, I thought about extend my classes, but not wrap them in a 
RefCountedObject

And indeed, it should also solve my problem of releasing cached resources.

I will try that.

Thx again.

Original comment by tetra...@gmail.com on 4 Sep 2012 at 10:18