When using GMS’s Python script, I’ve noticed that the global image variable must be manually deleted (using something like del image
) to free up memory. If this step is skipped, the variable remains in memory indefinitely, potentially causing memory issues.
For DM script, I have the following questions:
Failed Attempts:
Any insights or best practices regarding memory management in DM script would be greatly appreciated.
No.
The only thing that lingers in memory are object variables declared on the main-script (i.e. not within {}
)
The latter can lead to an image being kept in memory, if the object holds an image.
You can test this with the following example script:
Class CMemoryHog
{
image img
CMemoryHog(object self){ Result("\n Script object created:\t"+self.ScriptObjectGetID()); img:=realImage("Test",4,100,100);}
~CMemoryHog(object self){ Result("\n Script object destroyed:\t"+self.ScriptObjectGetID()); }
}
ClearResults()
Result("\n# Test1: Images in memory:"+CountImages())
Alloc(CMemoryHog)
Result("\n# Test1: Images in memory:"+CountImages())
{
Result("\n\n\n# Test2: Images in memory:"+CountImages())
Object ob1 = Alloc(CMemoryHog)
Result("\n# Test2: Images in memory:"+CountImages())
}
Result("\n\n\n# Test3: Images in memory:"+CountImages())
Object ob2 = Alloc(CMemoryHog)
Result("\n# Test3: Images in memory:"+CountImages())
Test1 allocates the object, but immediately destroys it afterwards.
Test2 allocates the object and references it by a local variable, but that variable gets removed once the local scope is left.
Test3 allocates the object and references it by a "global" variable. Global object variables stay in scope when the script ends.
The following script can be useful to "watch out" for images that are kept in scope (even if they are not displayed):
Class CMemLeakWatch : UIFrame{
CMemLeakWatch(object self) {Result("\n Created object '"+self.ScriptObjectGetClassName()+"' #"+self.ScriptObjectGetID());}
~CMemLeakWatch(object self) {Result("\n Destroyed object '"+self.ScriptObjectGetClassName()+"' #"+self.ScriptObjectGetID());}
number taskID
object Launch(object self, number refreshrate_sec){
string name = "Memory Leak Watch"
TagGroup DLGtgs, DLGItems
DLGtgs = DLGCreateDialog( name, DLGItems )
DLGItems.DLGAddElement( DLGCreateTextBox(40,10,0).DLGIdentifier("ListField") )
self.Init(DLGtgs)
self.Display(name)
taskID = self.AddMainThreadPeriodicTask("UpdateMem",refreshrate_sec)
return self
}
void AboutToCloseDocument(object self){ RemoveMainThreadTask(taskID);}
void UpdateMem(object self){
string listStr
for( number i=0; i<CountImages(); i++){
image img := FindImageByIndex(i)
if (img.ImageIsValid())
listStr += "[" + img.ImageGetLabel()+"]:"+img.ImageGetName()+"\n"
}
self.SetTextElementData("ListField",listStr)
}
}
Alloc(CMemLeakWatch).Launch(0.2)
``