Object with data member that contains Self

BlitzMax Forums/BlitzMax Programming/Object with data member that contains Self

Htbaa(Posted 2008) [#1]
OK, hope the topic title isn't too confusing. Let me explain by code.

'The test type
Type TA
	'Data member
	Field child:TB
	Global counter:Int
	
	Method New()
		TA.counter:+1
	End Method
	Method Delete()
		TA.counter:-1
	End Method
End Type

'Type that contains a reference to it's parent
Type TB
	Field m_main:TA
	Method SetMain(main:TA)
		Self.m_main = main
	End Method
End Type

'Test function
Function Test(set_main:Int = False)
	Local obj:TA = New TA
	obj.child = New TB
	'Make a reference is set_main = True
	If set_main = True
		obj.child.SetMain(obj)
	End If
	'Enable this line to fix the problem
	'But shouldn't deleting the parent object
	'already have to do this?
	'obj.child = Null
	'Destroy object
	obj = Null
	'Force garbage collection for instantly deleting objects
	GCCollect()
End Function

'----------------------------
Test()
'Should print 1
Print TA.counter

'----------------------------
Test(True)
'Should print 1 because the data member did not contain a reference
Print TA.counter

'----------------------------
'I expect it to print 1, but it does print 2
'The data member contains a reference to the parent
'But since the parent has been nullified I expect
'it to get cleared as well
Test(True)
Print TA.counter

'----------------------------
'Prints 3. But if the last result would've printed 1
'then this would also result in 1
Test()
Print TA.counter



So in short, you have an object that has a data member which in turn keeps a reference to its parent. I noticed that when setting the reference in the child data member and then deleting the parent doesn't destroy the objects.

Is this supposed to happen? The reference counters for both the parent and child should be set to 0 after killing the parent wouldn't it? Because what's happening now is memory leakage.

Is my understanding of the garbage collector wrong or is this a bug? If this is intended behavior then how can I work around this issue? When Nullifying the child first and then the parent does seem to fix it. But what if you have a whole lot more data members? Shouldn't nullifying the parent have to do this?

I'm using BlitzMax 1.30 by the way.


Azathoth(Posted 2008) [#2]
Its a problem with cyclic references, the parent and the child both have references to eachother.


Htbaa(Posted 2008) [#3]
Yes I understand that. But why won't the child get cleared when the parent is gone?


Azathoth(Posted 2008) [#4]
But the parent isn't gone, the child still contains a reference to it.


plash(Posted 2008) [#5]
Because BlitzMax is silly.


Azathoth(Posted 2008) [#6]
Because BlitzMax is silly.
Its not limited to BlitzMax.

Edit: Its a problem in many reference counting GC languages, some can handle cyclic references BlitzMax obviously doesn't.


Htbaa(Posted 2008) [#7]
Azathoth, that might be true BUT, there's no accessible variable that contains the address to the child.

But I think I get it. If you kill the parent the child is still there, although not accessible since there's no variable with its address. Since the child still refers to the parent and the parent still refers to the child they stay referenced. Even though they're not accessible in code anymore, their "memories" live on in memory.

Even so, shouldn't the garbage collector free the memory of variables that have become inaccessible?


Azathoth(Posted 2008) [#8]
Thats why cyclic references can be a problem, you could add a destroy method to your class that you explicitly call that nils the reference to child.
Until BlitzMax's GC can detect cyclic references you have to resolve them yourself.


Htbaa(Posted 2008) [#9]
OK, that's fine. Good to know that the GC doesn't handle cyclic references well. Thanks.