Wizzup?
2011-02-09 16:39:50
Hey there,
In the light of the Simba "code:8" error some people have been getting, I came up with an idea that might help reduce leaks (read: memory leaks) in Reflection. Why? Because I believe that there are memory management issues left in the Reflection include. Code "8" means out of memory; so something must be leaking… And since as far as I know this only happens with Reflection-based scripts, something might just be wrong with our reflection include. I may be completely wrong, but this idea will prove whether I am or not.
As you may (or may not) know, bitmaps (and dtms, but I'll just say bitmaps) in Simba are managed. That means, you can allocate them. (Call CreateBitmap/LoadBitmap/CreateBitmapFromString); and Simba will return you an integer. That's actually pretty weird if you've done coding in an other language, because a bitmap isn't really an integer, right? Normally, you'd expect it to return a "TBitmap" or similar bitmap instance. (For the record: you can actually get the object associated with the bitmap with GetMufasaBitmap) We try to avoid this in Simba for two reasons: To make memory management easier (generally) and to prevent crashes (working with non existent bitmaps) Obviously this only works partially because you'll still have to call FreeBitmap; Simba will only free unfreed bitmaps at the end of the script because it cannot know if you still want to use them before the script stops; but that is another story. It could (in theory, it doesn't do this atm) however, let you know what bitmaps are currently in use. And if you have no bitmaps or dtms; then this number should generally be 0. (Unless you're in a function that uses that bitmap, but you get my point)
To give you an idea on how this is done in Simba: (I'll only include the body of the important functions)
So, simply put: It's an array of the references to the real bitmap instances; indexed by (obviously) an integer. Which is funnily enough also the integer that you use in your script.
I want to propose the same for Reflection. Although I must admit I do not know the complete details as to how the SmartGetFieldObject (or similar) functions work; I think it should be quite easy to add a system like this. I'm willing to write this as well, but I'll have to gain some more understanding as to how SMART objects work. It would also be a big advantage (IMO) if we could (or, must?) ``label'' the objects, much like here: Debugging memory leaks in Simba
Oh, I just looked in the SMART source code and I see all the ``objects'' are just integers as well, which means we should be able to manage them quite well. Perhaps SMART already has a method to manage this, just not for debugging. (If the integers are indices; if they aren't, we can still manage them; but SMART perhaps doesn't. I wouldn't be surprised if it didn't since Java manages memory as well…)
Any thoughts?
In the light of the Simba "code:8" error some people have been getting, I came up with an idea that might help reduce leaks (read: memory leaks) in Reflection. Why? Because I believe that there are memory management issues left in the Reflection include. Code "8" means out of memory; so something must be leaking… And since as far as I know this only happens with Reflection-based scripts, something might just be wrong with our reflection include. I may be completely wrong, but this idea will prove whether I am or not.
As you may (or may not) know, bitmaps (and dtms, but I'll just say bitmaps) in Simba are managed. That means, you can allocate them. (Call CreateBitmap/LoadBitmap/CreateBitmapFromString); and Simba will return you an integer. That's actually pretty weird if you've done coding in an other language, because a bitmap isn't really an integer, right? Normally, you'd expect it to return a "TBitmap" or similar bitmap instance. (For the record: you can actually get the object associated with the bitmap with GetMufasaBitmap) We try to avoid this in Simba for two reasons: To make memory management easier (generally) and to prevent crashes (working with non existent bitmaps) Obviously this only works partially because you'll still have to call FreeBitmap; Simba will only free unfreed bitmaps at the end of the script because it cannot know if you still want to use them before the script stops; but that is another story. It could (in theory, it doesn't do this atm) however, let you know what bitmaps are currently in use. And if you have no bitmaps or dtms; then this number should generally be 0. (Unless you're in a function that uses that bitmap, but you get my point)
To give you an idea on how this is done in Simba: (I'll only include the body of the important functions)
TMBitmaps = class(TObject)
protected
Client : TObject;
FreeSpots : Array of integer;
BmpArray : TMufasaBmpArray;
BmpsCurr,BmpsHigh,FreeSpotsHigh,FreeSpotsLen : integer;
function GetNewIndex : integer;
public
function GetBMP(Index : integer) : TMufasaBitmap;
property Bmp[Index : integer]: TMufasaBitmap read GetBMP; default;
function CreateBMP(w, h: integer): Integer;
function AddBMP(_bmp: TMufasaBitmap): Integer;
function CopyBMP( Bitmap : integer) : Integer;
function CreateMirroredBitmap(bitmap: Integer; MirrorStyle : TBmpMirrorStyle): Integer;
function CreateBMPFromFile(const Path : string) : integer;
function CreateBMPFromString(width,height : integer; Data : string) : integer;overload;
function CreateBMPFromString(BmpName : string; width,height : integer; Data : string) : integer;overload;
procedure FreeBMP( Number : integer);
constructor Create(Owner : TObject);
destructor Destroy;override;
end;
{ snip }
function TMBitmaps.GetNewIndex: integer;
begin
if BmpsCurr < BmpsHigh then
begin;
inc(BmpsCurr);
Result := BmpsCurr;
end else if (FreeSpotsHigh > -1) then
begin;
Result := FreeSpots[FreeSpotsHigh];
dec(FreeSpotsHigh);
end else
begin;
SetLength(BmpArray, BmpsHigh + 6);
BmpsHigh := BmpsHigh + 5;
inc(BmpsCurr);
Result := BmpsCurr;
end;
end;
function TMBitmaps.GetBMP(Index: integer): TMufasaBitmap;
begin
Result := nil;
if (Index >= 0) and (Index <= BmpsCurr) then
if BmpArray[Index] <> nil then
Result := BmpArray[Index];
if Result = nil then
raise Exception.CreateFmt('The bitmap[%d] does not exist',[Index]);
end;
function TMBitmaps.CreateBMP(w,h : integer): Integer;
begin
result := GetNewIndex;
BmpArray[Result] := TMufasaBitmap.Create;
BmpArray[Result].SetSize(w,h);
BmpArray[Result].Index:= Result;
end;
function TMBitmaps.AddBMP(_bmp: TMufasaBitmap): Integer;
begin
Result := GetNewIndex;
BmpArray[Result] := _bmp;
BmpArray[result].Index:= Result;
end;
procedure TMBitmaps.FreeBMP(Number: integer);
var
ToDestroy : TMufasaBitmap;
begin
ToDestroy := GetBMP(Number);
if Number = BmpsCurr then
Dec(BmpsCurr)
else
begin;
inc(FreeSpotsHigh);
if FreeSpotsHigh = FreeSpotsLen then
begin;
inc(FreeSpotsLen);
SetLength(FreeSpots, FreeSpotsLen);
end;
FreeSpots[FreeSpotsHigh] := Number;
end;
//Just for testing purposes
{$ifdef mDebug}
if ToDestroy.BmpName = '' then
mDebug(Format('BMP[%d] has been freed.',[number]))
else
mDebug(Format('BMP[%s] has been freed.',[ToDestroy.BmpName]));
{$endif}
ToDestroy.Free;
BmpArray[number] := nil;
end;
So, simply put: It's an array of the references to the real bitmap instances; indexed by (obviously) an integer. Which is funnily enough also the integer that you use in your script.
I want to propose the same for Reflection. Although I must admit I do not know the complete details as to how the SmartGetFieldObject (or similar) functions work; I think it should be quite easy to add a system like this. I'm willing to write this as well, but I'll have to gain some more understanding as to how SMART objects work. It would also be a big advantage (IMO) if we could (or, must?) ``label'' the objects, much like here: Debugging memory leaks in Simba
Oh, I just looked in the SMART source code and I see all the ``objects'' are just integers as well, which means we should be able to manage them quite well. Perhaps SMART already has a method to manage this, just not for debugging. (If the integers are indices; if they aren't, we can still manage them; but SMART perhaps doesn't. I wouldn't be surprised if it didn't since Java manages memory as well…)
Any thoughts?
