Can any of these 5 functions cause "Out of memory" error?

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
User avatar
Brazolek123
Posts: 187
Joined: 06 Jun 2016, 16:02

Can any of these 5 functions cause "Out of memory" error?

11 Oct 2017, 16:44

I got main scritp that uses these functions from time to time. Files that are being read are monsters.xml and items.xml, which I will upload as attachments (items is quite long, 1,5MB whereas monsters is just list of few hundreds names and small xml file location path of each name).

The problem is that script once in one or two hours is stopping and I can't do anything. Clicking any button causes to appear msgbox with message: "Out of memory".

I wondering if it might be anywhere in this newly added code - bestiary:

Code: Select all

getCorpseType_bestiary(monster){
	monster := Trim(monster)
	corpseID := getData_bestiary(monster, "monster/look", "corpse")
	needleStr = `<item id`=`"%corpseID%
	itemsListfile := A_scriptDir . "/Data/monsters/items.xml"
	if fileexist(itemsListfile){
		FileRead, itemsList, %itemsListfile%
		Loop, parse, itemsList, `n, `r 
		{
			If (instr(A_LoopField,needleStr)){
				StringGetPos, start, A_LoopField, name`=`"
				StringGetPos, end, A_LoopField, `"`> 
				path :=  SubStr(A_LoopField, start+7, end - start -6)
				if InStr(path, "dead")
					return "dead"
				else if InStr(path, "remains")
					return "remains"
				else if InStr(path, "slain")
					return "slain"
				else if InStr(path, "split")
					return "split"
			}
		}
	}
	Console("Function error: getCorpseType_bestiary() - monster " . monster . " not recognized. Please report error to the support team.") 
	return "dead"
}

monsterExist_bestiary(monster){
	monster := Trim(monster)
	monName = `"%monster%`"
	monstersListFile := A_scriptDir . "/Data/monsters/monsters.xml"
	if fileexist(monstersListFile){
		FileRead, monstersList, %monstersListFile%
		Loop, parse, monstersList, `n, `r 
		{
			If (instr(A_LoopField,monName)){
				return 1
			}
		}
	}
	return 0
}



getFile_bestiary(monster){
	monster := Trim(monster)
	monName = `"%monster%`"
	monstersListFile := A_scriptDir . "/Data/monsters/monsters.xml"
	if fileexist(monstersListFile){
		FileRead, monstersList, %monstersListFile%
		Loop, parse, monstersList, `n, `r 
		{
			If (instr(A_LoopField,monName)){
				StringGetPos, start, A_LoopField, file`=`"
				StringGetPos, end, A_LoopField, `" `/`> 
				path :=  SubStr(A_LoopField, start+7, end - start -6)
				return path
			}
		}
	}
	return 0
}

getData_bestiary(monster, xml_path, attribute){
	; edited attribute xml reader by Joedf @ahk forum
	monster := Trim(monster)
	if !(monsterExist_bestiary(monster))
		return 0
	FileRead, xmldata, % A_ScriptDir . "\" . getFile_bestiary(monster)
	doc := ComObjCreate("MSXML2.DOMDocument.6.0")
	doc.async := false
	doc.loadXML(xmldata)
	DocNode := doc.selectSingleNode("//" . xml_path)
	return DocNode.getAttribute(attribute) 
}

getLoot_bestiary(monster, type:=0){ ;specify 0 for all, 1 for nonstackable and 2 for stackable; not work that good, if caount max =1 item is not considered as stackable
	monster := Trim(monster)
	FileRead, xmldata, % A_ScriptDir . "\" . getFile_bestiary(monster)
	lootlist :=""
	needleStr=`<item name`=`"
	Loop, parse, xmldata, `n, `r 
	{
		If (instr(A_LoopField,needleStr)){
			if (type = 0){
				if (InStr(A_LoopField, "countmax")){
					StringSplit, lootItem, A_LoopField, `"
					if lootItem2 != gold coin
						lootlist .= lootItem2 . ","
				}
			}
			else if (type = 1){
				if !(InStr(A_LoopField, "countmax")){
					StringSplit, lootItem, A_LoopField, `"
					if lootItem2 != gold coin
						lootlist .= lootItem2 . ","
				}
			}
			else{
				StringSplit, lootItem, A_LoopField, `"
				if lootItem2 != gold coin
					lootlist .= lootItem2 . ","
			}
		}
	}
	xmldata :=""
	return lootlist
}
Attachments
items.xml
(1.51 MiB) Downloaded 57 times
monsters.xml
(72.1 KiB) Downloaded 54 times
User avatar
Brazolek123
Posts: 187
Joined: 06 Jun 2016, 16:02

Re: Can any of these 5 functions cause "Out of memory" error?

12 Oct 2017, 10:19

I sit for a moment at my script and created log function:

Code: Select all

log(funcname, label, step:=0){
   logMsg := A_TickCount . "," GetProcessMemory_Private()  . "," . funcname  . "," . label  . "," . step
   FileAppend, `n%logMsg%, logfile.txt
}

GetProcessMemory_Private(Units="K") {
    pid :=DllCall("GetCurrentProcessId")
    ; get process handle
    hProcess := DllCall( "OpenProcess", UInt, 0x10|0x400, Int, false, UInt, pid )
    ; get memory info
    PROCESS_MEMORY_COUNTERS_EX := VarSetCapacity(memCounters, 44, 0)
    DllCall( "psapi.dll\GetProcessMemoryInfo", UInt, hProcess, UInt, &memCounters, UInt, PROCESS_MEMORY_COUNTERS_EX )
    DllCall( "CloseHandle", UInt, hProcess )
    SetFormat, Float, 0.0 ; round up K
    PrivateBytes := NumGet(memCounters, 40, "UInt")
    if (Units == "B")
        return PrivateBytes
    if (Units == "K")
        Return PrivateBytes / 1024
    if (Units == "M")
        Return PrivateBytes / 1024 / 1024
}
The result of this log is present in this excel chart:
Image

And I don't understand a few things:
1) What might be the reason that script still increases its RAM usage linneary so long after its launch? Im not IT specialist but the script looks like this: since my script starts, I change some basic setting, set it on run and it only repeats the same steps in a loop. So it should reach its maximum RAM usage in the first two minutes since start, not in hour.

2) Also the peak at t=3660 wasn't the moment of crash. Script was still executing after that without problems for the next 5-10 minutes. It stopped just minute or two before log ends.

3) There wasn't any crash window or anything. Script just stopped working, but GUI was still usable, few buttons didn't work (examplery the one with bestiary function printed "out of memomry" error).

4) Alternate use of gdip.ahk and imagesearch may be the cause?
Noesis
Posts: 301
Joined: 26 Apr 2014, 07:57

Re: Can any of these 5 functions cause "Out of memory" error?

13 Oct 2017, 00:48

I'm not exactly sure why the script malfunctions, and without the full code I'd have no way of being sure, for example, you mention gdip being used but there is no mention of it being used in the posted code.

Essentially the memory being used in the way indicated by the graph suggests that there is some memory being used somewhere which isn't released (i.e memory leak), likely a variable somewhere, that is referencing something, and that something the variable references isn't being freed, but instead the variable is simply reassigned to a new instance (copy) of whatever it's referencing.

It's a bit of guess as it could also be the files being read, if they're essentially static files then the above would apply but if they get bigger during the scripts run time, then that is another potential reason. I'd suggest you alter the code in a way that ensures that all the variables referencing external objects are explicitly freed before returning from the functions that create those references, and make sure any values you are returning are actually values and not external object references. Essentially you need to make sure all memory references are cleared while the script executes, an not rely on the fact they will auto clear on script exit. (but if you wanted to be lazy you'd probably find you could just implement a restart script hotkey, to auto clear the memory.)

Also, in a situation like this, just because the error is presenting itself with the bestiary function, it doesn't necessarily mean it is occurring within that code, all that is really known is that it can no longer do that function due to too much memory being used. Where that memory is being used is the real issue.

Return to “Ask for Help (v1)”

Who is online

Users browsing this forum: filipemb, Google [Bot], mikeyww and 322 guests