mixster
2009-05-14 22:43:36
I've been working with bitmaps a lot recently and debugging memory leaks became quite a big thing to do, so I decided to make a self debugging method of catching these annoying misses.
There are two global variables used to keep track of the information, this being
It doesn't seem like much, but it can help a lot to find memory leaks and also shows ones that you may have missed. Also, it can be modified to support DTM creating and freeing as well as other forms of bitmap loading.
Lastly, I've used it a lot and it hasn't shown any problems. It handles it fine when bitmaps are created aside from using it and all that stuff, so I don't see any problem it can run into. The only possible one will be when you free the bitmap without using the MFreeBitmap procedure as it will assume it's still in use then try to free it at the end, though can be fixed by surrounding in a try..except..end (I prefer to leave it in so it notifies me that I freed it elsewhere first) or removing the freeing at the end.
~Enjoy
function MBitmap(w, h: Integer; str, from: string): Integer; // Creation half of the memory leak debugging
begin
Result := BitmapFromString(w, h, str); // Start by actually making the bitmap since we need the reference number
while (Length(bitDeb) < Result + 1) do // While the string is too short
bitDeb := bitDeb + '2'; // Increase the length of the string by adding a 2 which signifies bitmap created by alternate means
bitDeb[Result + 1] := '1'; // Set the index to 1 to signify in use - string's start at 1 not 0, hence the + 1
SetLength(bitLoc, Length(bitDeb) + 1); // This is 1 longer than the string due to it starting on 0 and me wanting them in line
bitLoc[Result + 1] := from; // Set where the bitmap was created from
end;
^ is for handling the creation of new bitmaps - the first three variables related directly to BitmapFromString with the last just being the procedure where it is created, though it really can hold any identifier to show where it is created in order to find it.
procedure MFreeBitmap(b: Integer); // Destroying half of the memory leak debugging
begin
FreeBitmap(b); // Start by freeing it as the reference remains afterwards
b := b + 1 // Increment it to line it up with the arrays
if (b > Length(bitDeb)) then // If the debug string is too short
exit; // Then we don't need to change anything (created by LoadBitmap or something similar) so exit procedure
bitDeb[b] := '0'; // Set to 0 to signify not in use
bitLoc[b] := ''; // Set to blank
end;
^ This handles the freeing of the bitmap.There are two global variables used to keep track of the information, this being
bitDeb: string; // Holds the string that has the info about all the bitmaps currently in use
bitLoc: TStringArray; // Holds the location from where the relating bitmap was created
It could be put all into one global variable, but I prefer the ease of use of using a string to hold the status of the bitmap as it's easier to access, though must be careful with the index in the string relating to index - 1 in the array.
while True do
begin
i := Pos('1', bitDeb);
if (i = 0) then
Break;
Writeln('Bitmap created from ''' + bitLoc[i] + ''' not freed!');
MFreeBitmap(i - 1);
end;
^ This is then used at the end of the script when everything should be freed already and the like to see which ones weren't.It doesn't seem like much, but it can help a lot to find memory leaks and also shows ones that you may have missed. Also, it can be modified to support DTM creating and freeing as well as other forms of bitmap loading.
Lastly, I've used it a lot and it hasn't shown any problems. It handles it fine when bitmaps are created aside from using it and all that stuff, so I don't see any problem it can run into. The only possible one will be when you free the bitmap without using the MFreeBitmap procedure as it will assume it's still in use then try to free it at the end, though can be fixed by surrounding in a try..except..end (I prefer to leave it in so it notifies me that I freed it elsewhere first) or removing the freeing at the end.
~Enjoy