Do Type pointers within Types get nulled?
BlitzMax Forums/BlitzMax Programming/Do Type pointers within Types get nulled?
| ||
I could probably test this but someone may have a quick answer. Say I have a type A, and one of it's fields (called P) points to another type B. Then I make an instance of type A and Type B, then I do A.P = B. Then later on I do B=null, I know that the GC won't collect it because A.P still exists. So my question is, if I do A=Null will Bmax automatically do A.P=null so that B can be GCed or do I have to "manually" free up any such type pointers. Thanks. I've been working on the theory than you don't need to manually free them (unless they contain something that need special behaviour like Sound Channels or maybe lists (can't remember if MyList=null is safe or if you have to use MyList.Clear() so I always use Clear()). |
| ||
You could probably have tested it in less time than it took you to write the post. Anyway yes, a.p will be nulled. <edit> Now do you trust I am right or test that I'm right? Type typea Field p:typeb End Type Type typeb Field x:Int=5 EndType For Local loopy:Int = 0 To 2000 a:typea = New typea b:typeb = New typeb a.p = b b = Null a = Null GCCollect() Print GCMemAlloced() Next (remove gccollect to see memory being obtained and released) :-) |
| ||
Thanks. Hmm, If I comment out b=null and a=null then the memory doesn't go up because they are local variables. I'll make another test... |
| ||
here's a test. It never goes back to the start memory. Why not?Strict Type typea Field p:typeb End Type Type typeb Field x:Int=5 EndType DisplayMem("start") Local a:typea = New typea DisplayMem("a created") Local b:typeb = New typeb DisplayMem("b created") a.p = b b = Null DisplayMem("b nulled") a = Null DisplayMem("a nulled") Function DisplayMem(label$="") GCCollect() Print GCMemAlloced() + " " + label End Function If you add in a.p = null it still doesn't got back down. Seems like A isn't out of scope or something. |
| ||
OK stuck the test in a function to ensure that A goes out of scope:Strict Type typea Field p:typeb End Type Type typeb Field x:Int=5 EndType DisplayMem("start") Test() DisplayMem("end") Function Test() Local a:typea = New typea DisplayMem("a created") Local b:typeb = New typeb DisplayMem("b created") a.p = b b = Null DisplayMem("b nulled") a = Null DisplayMem("a nulled") End Function Function DisplayMem(label$="") GCCollect() Print GCMemAlloced() + " " + label End Function This shows that a.p is automatically nulled. |
| ||
Aren't you creating string objects which are GC by doing gcmemalloced+" "+ label? <edit> and would my local variables not go out of scope after the gccollect/gcmemalloced. Never mind. You've answered your own questions. |
| ||
Be careful of circular references tho. ie.a.p = b b.p = a They won't get garbage collected (or nulled), unless you go: a.p = null b.p = null |
| ||
yeah I have been very carefull to avoid those thanks. And where they are used (e.g. a list item pointing back to the list it's part of) I've made sure the list item has a Kill() method that nulls the pointer to the list so that when the list items are freed the main list variable is the only pointer left. |
| ||
Actually you only need to free up one of the pointers as the other one will get auto-nulled when the type is destroyed. See this code:Strict Type test Field p:test End Type DisplayMem("start") testfunc() DisplayMem("end") Function testfunc() Local a:test = New test Local b:test = New test a.p = b b.p = a ' a.p = Null 'uncomment this to see the circular ref fixed. End Function Function DisplayMem(label$="") GCCollect() Print GCMemAlloced() + " " + label End Function |
| ||
Of course. :) |
| ||
well I didn't know that until today and found out by accident. Thanks Beaker. |
| ||
Ok - I'm going little crazy now...Strict GCCollect() Print GCMemAlloced() Type mio Field valore:Int Field link:TLink End Type Local lista:tlist=New tlist Local mi:mio = New mio ListAddLast lista,mi ClearList(lista) mi = Null lista=Null GCCollect() Print GCMemAlloced() I run this code (with debug mod off) and I have the following results: 12060 12060 - good! Then I make the SAME code with methods Strict GCCollect() Print GCMemAlloced() Type mio Field valore:Int Field link:TLink End Type Local lista:tlist=New tlist Local mi:mio = New mio lista.addlast mi lista.clear mi = Null lista=Null GCCollect() Print GCMemAlloced() I have the following results: 12060 - 12092 Why? What's wrong with this source? |
| ||
Well, that is pretty weird, since .addlast is all that ListAddLast does and .clear is all that ClearList does (which you doubtless already know <g>). I get similar results. The good news (I guess) is that it's a one-time effect. If you stick a For/Next loop around everything from "Local lista:tlist=New tlist" to "Print GCMemAlloced()" for 100 iterations in both programs, the memory doesn't go up each time. So it doesn't seem to be a "true" leak. Check this, though. It's able to free up more memory than you started with by Null-ing the contents of the type instance before Null-ing the instance itself (even though they're already Null since they've never been assigned values): Strict GCCollect() Print GCMemAlloced() Type mio Field valore:Int Field link:TLink End Type Local lista:TList=New TList Local mi:mio = New mio ListAddLast lista,mi ClearList(lista) mi.valore = Null mi.link = Null mi = Null lista=Null GCCollect() Print GCMemAlloced() I get: 13960 13956 All this is weird. I could be wrong (easily!) but I'm thinking that it might just be a glitch with byte boundaries or something and isn't significant. It'd be nice to know what's really going on just for curiosity's sake, but it doesn't seem to be a real problem since it's a one-time deal that doesn't change when done multiple times. |
| ||
No, it's not a real problem (the difference is really small), but it is the fact that methods are called by ListClear() and the results should be the same (I think!)!!! Well the good new is I'm not going crazy... Thanks! |
| ||
It's not a valid test. You must run the test in a function otherwise the Local variables will NOT be freed up, even when you call GCCollect(). I found this out when making my own tests early on:Strict GCCollect() Print GCMemAlloced() Type mio Field valore:Int Field link:TLink End Type f() GCCollect() Print GCMemAlloced() Function f() Local lista:TList=New TList Local mi:mio = New mio lista.addlast mi lista.clear mi = Null lista=Null End Function gives: 14948 14948 |
| ||
Oh! Thanks Grey! Now it's more clear! So having Global in the 'main' source (like in my example) doesn't guarantee the memory allocated is then freed up correctly? I need to make some test... Thanks anyway |
| ||
yeah basically globla or local in the main source doesn't guarantee it being cleared, whereas it will be cleared if in a function. |