ID:2074904
 
(See the best response by Kaiochao.)
Code:
proc
ThrowWeapon(mob/thrower,obj/weapon)
var/obj/Projectiles/Weapons/W = new weapon.projectile_type
//obj's New() proc is not modified - no other variables set AFAICT
W.Owner = thrower //Side note: is setting a mob as a var for an object OK to do?
W.loc = thrower.loc
W.step_x = thrower.step_x
W.step_y = thrower.step_y
W.dir = thrower.dir
//In this example, there are no walk() or other movement procs being used (yet)
spawn(10)
GarbageCollect_ThrownWeapon(W)

GarbageCollect_ThrownWeapon(obj/o)
o.Owner = null
o.loc = null
o.step_x = null //do I even need to set these to null?
o.step_y = null // "
o.dir = null // "

spawn(500) //Tried delaying the test, don't know how often collection happens...
GarbageCollectionTest()
//could I have this as: GarbageCollection(o)?
//and skip the for() loop below?

GarbageCollectionTest()
for(var/obj/Projectiles/o in world)
if(o)
debug("Not collected")
else
debug("Collected")//EDIT: Just realised I am a dingus, this line will never be called!


Problem description:
So I've resolved to have proper garbage collection in my project, rather than relying on del. I know there're some threads on it, and Ter13 talks about it a lot, but the info was a little advanced for where I am right now, and I couldn't work out how to apply it yet -sorry!

As far as I can tell, there are no variables left un-nulled, but the collection test proc returns positive.

Is there something I can do to output what vars are yet to be nulled?
How often does garbage collection occur?
Is this a good way of testing for garbage collection?
Would walk(obj,dir) impede garbage collection (not used in the above code yet, but it will be)?
Do I really need to nullify dir and step_x/y?

Answers to the above and anything else relevant would be so appreciated!

Cheers

Edit: I just noticed that, on subsequent uses, "Not Collected" only outputs once each time - suggesting that maybe it has been garbage collected??

I get the same results (one output per call) if I don't nullify "Owner", but get exponential calls if I don't nullify loc.

Not sure what to make of this / why it doesn't just output "Collected"...
Garbage collection happens on objects that have no references to them, not references to other things.

For example, if you have this code:
var datum/o = new // o contains some new /datum instance
o = null // o no longer refers to that /datum instance (o doesn't have to be null, just anything other than the datum)
...
// now how do we access the datum that was created?

Answer: we can't, so it's garbage collected. Its existence is meaningless/wasted memory because we couldn't use it even if we wanted to, after losing all references to it.
In response to Kaiochao
Kaiochao wrote:
Garbage collection happens on objects that have no references to them, not references to other things.

For example, if you have this code:
> var datum/o = new // o contains some new /datum instance
> o = null // o no longer refers to that /datum instance (o doesn't have to be null, just anything other than the datum)
> ...
> // now how do we access the datum that was created?
>

Answer: we can't, so it's garbage collected. Its existence is meaningless/wasted memory because we couldn't use it even if we wanted to, after losing all references to it.

If there's a reference to an object on a proc, would it stop existing once proc's concluded? Ex.:

proc/Create_Object()
var/obj/O = new/obj (locate(1,1,1))
O.icon = 'Square.dmi'
O.layer = 5
spawn(10) O.loc = null //would it make it stop existing once proc has ended?


In response to Kaiochao
Kaiochao wrote:
Garbage collection happens on objects that have no references to them, not references to other things.
Ah, of course, that makes more sense - but I still have many of my original questions...

I can now reframe my code/question like this: How come this doesn't output "Collected"?
proc
GarbageCollect_ThrownWeapon(obj/o)
o.loc = null

spawn(50)
GarbageCollectionTest()

GarbageCollectionTest()
var/c=0
for(var/obj/Projectiles/o in world) c++
if(c>0) debug("Not collected")
else debug("Collected")


* What is the best way to confirm/check garbage collection (in case I later break it, and have millions of objs piling up)?
* How frequently does garbage collection occur? Is it instant once the requirements are met? Is it once per world tick?


Edit: After much trial and error, I think I've answered my own questions:

Garbage collection is instant.
For unknown reasons, calling the test proc output a false negative (I have no idea why).
By adding a boolean var, set to true when I intend to garbage collect - I can later have a for(obj in world) loop check if garbage collection was successful. But this proc must be called separately, I dont know why.

I guess this means I could have a once-per hour check to ensure collection (as for(x in world) loops have huge overhead)
In response to Saucepan Man
Best response
In GarbageCollect_ThrownWeapon(obj/o), o is a reference.

Del() is called for garbage-collected things. You could put a debug message there.

Dream Daemon has Memory Stats. It might be helpful in seeing when memory might be getting overused.

I don't know how often it occurs. Is it really important?
How do images work with this? You can't check if an image exists through for(...), thus you need a reference to check if it exists. How can you make sure it's been collected?
In response to ArmitxeX
Yeah. It's garbage collected after the proc ends, or as soon as you set O to null (after setting O.loc to null) since O is still a reference.

The important thing about setting o.loc to null is that o.loc is an atom that has a reference to o in its contents var, not that o.loc isn't null.
In response to Estarqui
/image objects exist in the client.images list for all clients that they have been shown to (and of course, any variables you might have made).
In response to Kaiochao
Kaiochao wrote:
/image objects exist in the client.images list for all clients that they have been shown to (and of course, any variables you might have made).

Thanks a lot :)
A proc's arguments, local vars, the . return var, usr, src, and two internal temp vars can all hold references too. The temp vars clear out if the proc sleeps or returns. Others end when the proc ends for good.
In response to Kaiochao
Oh of course! Del()! I forgot to consider it might go through that (I guess in my mind, del() was the only thing that used it on account of the names)

Its not overly important, but I'm looking to have the project use as little memory as possible, on the presumption that it will have better online performance?

Note: I was using a rather specific example here, but it was the pilot for having a goal of doing away with del() altogether, to maximise performance.