GC does not work how I thought it did

BlitzMax Forums/BlitzMax Programming/GC does not work how I thought it did

GfK(Posted 2009) [#1]
Note: I'm not using threading here, so standard GC is being used.

Consider this code:
Strict
Local x:myType
For Local N:Int = 1 To 50
	x = New myType
	x.timer._ticks = 0
	DebugLog "Passed iteration: " + N
Next


Type myType
	Field timer:ttimer
	
	Method New()
		Self.timer = CreateTimer(10)
	End Method
End Type

Now, I'm fully aware of the limit on the number of timers you can use, but that's not the issue - it just serves to highlight it. Using the code above, only one instance of myType should ever exist, and therefore, only one timer should ever exist.

After exactly 16 iterations every time, I get "attempted to access field or method of null object".

Why? Surely only one timer exists?

The code obviously executes in a fraction a second, but even in a real world scenario (of playing a game repeatedly over several minutes), it still dies after 16 iterations. I use two timers, and that's all there should ever be in existence, so should not be any problems.

[edit] Just tried threaded GC with identical results so I don't think its actually a GC problem. Also, no amount of manual garbage collecting seems to fix this, either.


Who was John Galt?(Posted 2009) [#2]
You can't make assumptions about when the garbage will be cleared. If you put a GCcollect() <assuming it still exists in Blitz?> in the loop, it may stop the error.


Thareh(Posted 2009) [#3]
You should call StopTimer( X.Timer ) before "freeing" it by overwriting your variable X with a new type.
Else it will probably not get GCed I think ^^


GfK(Posted 2009) [#4]
You can't make assumptions about when the garbage will be cleared. If you put a GCcollect() <assuming it still exists in Blitz?> in the loop, it may stop the error.
I would have thought it would be safe-ish to assume that GC would run at least once over a period of several minutes?

As I said (in my edit, so you may have missed it), manually calling GCCollect() doesn't improve the situation.

You should call StopTimer( X.Timer ) before "freeing" it by overwriting your variable X with a new type.
Oddly, that works - thanks. Be nice if GC didn't pick and choose what it wants to clean up.


matibee(Posted 2009) [#5]
I think timers have to be destroyed manually with StopTimer... this works fine..

Strict
Local x:myType
For Local N:Int = 1 To 50
	If ( x ) 
		StopTimer( x.timer )
	End if
	x = New myType
	x.timer._ticks = 0
	DebugLog "Passed iteration: " + N
Next


Type myType
	Field timer:ttimer
	
	Method New()
		Self.timer = CreateTimer(10)
	End Method
End Type



GfK(Posted 2009) [#6]
Sorted. Thanks all.