Can't pin down memory leak...desperate for help

BlitzMax Forums/BlitzMax Programming/Can't pin down memory leak...desperate for help

Tom Darby(Posted 2005) [#1]
Hello folks,

I've been pulling my hair out trying to find a memory leak, and I've managed to come reasonably close to isolating it here. Could somebody take pity on me and point out the (most likely obvious) reason the following program leaks memory like a sieve? It has -something- to do with the XML parser and the Clone() method, but I just can't pin down what it is...

A massive thanks in advance,

Tom



Type Brick

Field name$=""
Field spriteName$=""

Method Clone(brickToCloneFrom:Brick)

	name$ = brickToCloneFrom.name$
	spritename$ = brickToCloneFrom.spriteName$

End Method

Method LoadFromXML(XMLToLoadFrom$)
	
	SetStringFromXML(name$, XMLToLoadFrom$, "brickName")
	SetStringFromXML(spriteName$, XMLToLoadFrom$, "spriteName")

End Method

End Type

Type Game

	Field brickTemplates:TList
	Field currentBricks:TList

	Method Initialize()

		brickTemplates = CreateList()
		currentBricks = CreateList()
	
	End Method
	
	Method LoadTemplateData()
	
		Local i
		Local tmpBrick:Brick
		Local tmpXML$
		
		For i = 0 To 10
			tmpXML$ =  "<brick><brickName>foo" + i + "</brickName><spriteName>bar</spriteName></brick>"
			tmpBrick = New Brick
			tmpBrick.LoadFromXML(tmpXML$)
			ListAddLast(brickTemplates, tmpBrick)
		Next	
		
	End Method

	Method LoadLevelData()
	
		Local i
		Local tmpBrick:Brick, brickToClone:Brick
		Local tmpXML$
		
		currentBricks = CreateList()

		For i = 1 To 100
			tmpBrick = New Brick
			
			tmpXML$ =  "<brick><brickName>foo" + Rand(0, 10) + "</brickName></brick>"
			tmpBrick.LoadFromXML(tmpXML$)
						
			For brickToClone = EachIn brickTemplates
				If brickToClone.name$ = tmpBrick.name$ Then
					tmpBrick.Clone(brickToClone)	' clone from the template to get brick attributes.
					Exit
				EndIf
			Next
			ListAddLast(currentBricks, tmpBrick)
		Next

	End Method

End Type

Function SetStringFromXML(stringToSet:String Var, XMLToParse:String="", tagToRead:String="")

	Local tmpValue:String
	
	tmpValue$ = GetDataFromXML$(XMLToParse$, tagToRead$)
	
	If tmpValue$ <> "" Then
			stringToSet$ = tmpValue$
	EndIf

End Function


Function GetDataFromXML$(XMLtoParse:String="", tagToRead:String="")

	' finds LAST occurance of a given tag, returns the data as a string.  Use for filling values, NOT for grabbing trees
	' if rootOnly, then disregard nested tags.
'	Local tmpTimer:DebugTimer
'	tmpTimer = New DebugTimer
'	tmpTimer.StartTimer(tagToRead$)
	
	Local frontIndex:Int=0, backIndex:Int=0, dataToReturn:String=""
		frontIndex = XMLtoParse$.FindLast("<" + tagToRead$ + ">") + tagToRead$.length + 2
		backIndex = XMLtoParse$.FindLast("</" + tagToRead$ + ">")

	
	If (-1 < frontIndex And frontIndex < backIndex And backIndex <= XMLtoParse$.length)			
		dataToReturn$ = XMLtoParse$[frontIndex..backIndex]
		dataToReturn$.Replace("&lt;", "<")
		dataToReturn$.Replace("&gt;", ">")
		dataToReturn$.Replace("&tab;", "~t")
		dataToReturn$.Replace$("&line;", "~n")

		Return dataToReturn$
	Else
		Return Null
	EndIf

End Function

' main loop

Local keepPlaying:Int, tmpCount:Int, i:Int
Local currentGame:Game

keepPlaying = 1 
tmpCount = 0
currentGame = New Game

Graphics 1024, 768, 32, 0

While keepPlaying = 1
tmpCount = tmpCount + 1
	currentGame.Initialize()
	currentGame.LoadTemplateData()
	currentGame.LoadLevelData()

	FlushMem()
	Cls
	DrawText("Iteration " + tmpCount + "--memory Used: " + MemAlloced() + " bytes", 10, 10)
	Flip()

	If KeyHit(KEY_ESCAPE) > 0 Then
		keepPlaying = 0
	EndIf

Wend





Tom Darby(Posted 2005) [#2]
Narrowed it down even further: it seems to be this line causing the trouble:

dataToReturn$ = XMLtoParse$[frontIndex..backIndex]


EDIT: Managed to plug it using Mid(), but I'd really like to know why the sliced string wasn't working...

EDIT AGAIN: Wait, no, Mid() doesn't plug it. Still leaking. Damn.


Tom(Posted 2005) [#3]
Not sure why it's leaking but..

If you're declaring dataToReturn as a single string, how are you assigning a slice to it? Shouldn't you be using an Index instead?

This would pop an error surely?
dataToReturn$ = XMLtoParse$[frontIndex..backIndex]


Local a:String[5]
For Local i:Int = 0 To 4
  a[i] = String(i)
Next
Local s:String = a[1]
'Local s:String = a[1..2] 'or a[1..1], either doesn't work



Tom Darby(Posted 2005) [#4]
Tom:

You can slice strings as well as arrays; note that XMLtoParse$ is a string, not an array. Check [ BlitzMax Documentation >> Language Reference >> Slices ] for more on this.

The leak persists, however, whether I use string slicing or the Mid() function. Arrgh. This is a show-stopper for me (can't load my data files without leaking memory!)


BlitzSupport(Posted 2005) [#5]
I notice that if instead of commenting out...
dataToReturn$ = XMLtoParse$[frontIndex..backIndex]

... I comment out the next...
Return dataToReturn$

... it also plugs the leak. Could the problem be with whatever function is dealing with that returned data? Still poking cluelessly...

[MORE... ]

This may turn out to be useless, and a wander in the wrong direction, but... commenting out the stringToSet$ below, which is where the XMLToParse[] comes from (if I remember rightly), also stops it...

Function SetStringFromXML(stringToSet:String Var, XMLToParse:String="", tagToRead:String="")

	Local tmpValue:String
	
	tmpValue$ = GetDataFromXML$(XMLToParse$, tagToRead$)
	
	If tmpValue$ <> "" Then
'			stringToSet$ = tmpValue$
	EndIf

End Function

... and moving up to where that's passed from...

Method LoadFromXML(XMLToLoadFrom$)
	
'	SetStringFromXML(name$, XMLToLoadFrom$, "brickName")
	SetStringFromXML(spriteName$, XMLToLoadFrom$, "spriteName")

End Method

Disabling the above line stops it, while the other line is OK. I'm a bit stuck as to what happens from here... XML and parsing in general drives me nuts...


Tom(Posted 2005) [#6]
my bad!


Tom Darby(Posted 2005) [#7]
No problem. I think I've found a workaround--instead of returning the result, I'm passing a var parameter instead

[EDIT:] No, I haven't. Damn again.


skidracer(Posted 2005) [#8]
The version posted at the top does not leak for me, did you modify it or maybe my build of BlitzMax fixes it?


Tom Darby(Posted 2005) [#9]
skid:

...which build do you have? I just re-copy-and-pasted it and it's failed on me again. I'm running version 1.10, and it's leaking for me on OS X -and- on Windows. My modules are all up to date.


skidracer(Posted 2005) [#10]
I'm testing on the current inhouse version which will hopefully be ready for release in the next week or two.


Tom Darby(Posted 2005) [#11]
Thanks, Skid. I can't tell you how much that puts my mind at ease--it's a lucky thing I got my hair cut short a few days ago, or I'd be missing huge chunks of it right now...

Tom

/eagerly awaiting that release so I can start using FlushMem() again!