diff --git a/code/controllers/garbage.dm b/code/controllers/garbage.dm index 5117509857d..51b71b2c177 100644 --- a/code/controllers/garbage.dm +++ b/code/controllers/garbage.dm @@ -1,93 +1,91 @@ -#define GC_COLLECTIONS_PER_TICK 250 // how many objects we're going to null the vars of per tick -#define GC_COLLECTION_TIMEOUT 300 // deciseconds to wait to let running procs finish before we just say fuck it and force del() the object -#define GC_DEL_CHECK_PER_TICK 100 // number of tests per tick to make sure our GC'd objects are actually GC'd -#define GC_FORCE_DEL_PER_TICK 20 // max force del() calls per tick +#define GC_COLLECTIONS_PER_TICK 250 // Was 100 +#define GC_COLLECTION_TIMEOUT 100 // 10s var/global/datum/controller/garbage_collector/garbage - -var/list/uncollectable_vars=list( -// "bounds", // bounds and its ilk are all caught by the issaved() check later on +var/global/list/uncollectable_vars=list( + "alpha", + "bestF", + "bounds", + "bound_height", + "bound_width", + "ckey", + "color", "contents", - "gc_destroyed", - "invisibility", - "gender", // Causes runtimes if the logging is on + "gender", + "group", + "key", + //"loc", + "locs", + "luminosity", "parent", + "parent_type", "step_size", + "glide_size", + "gc_destroyed", + "step_x", + "step_y", + "step_z", + "tag", + "thermal_conductivity", + "type", + "vars", + "verbs", + "x", + "y", + "z", ) -// These are the vars left from /vg/'s implementation that aren't const or global -// I dunno how many are necessary but since most of these are numbers anyways, I don't care. - /datum/controller/garbage_collector - var/list/queue = list() // list of things that have yet to have all their vars nulled out - var/list/destroyed = list() // list of refID's of things that should be garbage collected - // refID's are associated with the time at which they time out and need to be manually del() - // we do this so we aren't constantly locating them and preventing them from being gc'd + var/list/queue=list() + var/list/destroyed=list() + var/waiting=0 + var/turf/trashbin=null -/datum/controller/garbage_collector/proc/AddTrash(var/atom/movable/A) - if(!istype(A)) - return -// testing("GC: AddTrash([A.type])") - queue |= A + New() + trashbin=locate(0,0,CENTCOMM_Z) -/datum/controller/garbage_collector/proc/Pop() - var/atom/movable/A = queue[1] - if(!A) - queue.Cut(1, 2) -// testing("GC: Pop() given null") - return - if(!istype(A,/atom/movable)) -// testing("GC: -- Pop() given [A.type] --") - queue.Cut(1, 2) - del(A) - return - for(var/vname in A.vars) - if(!issaved(A.vars[vname])) -// testing("GC: Skipping [vname] in [A.type]: it's const|global|tmp") - continue - if(vname in uncollectable_vars) -// testing("GC: Skipping [vname] in [A.type]: it's uncollectable") - continue -// testing("GC: Unsetting [vname] in [A.type]") - A.vars[vname] = null -// testing("GC: Pop([A.type]) - destroyed\[\ref[A]\] = [A.gc_destroyed] current time: [world.time] first:[queue[1]] second:[queue.len > 1 ? "[queue[2]]" : "NOTHING"]") - destroyed["\ref[A]"] = A.gc_destroyed - queue.Cut(1, 2) + proc/AddTrash(var/atom/movable/A) + if(!A) + return + A.loc=trashbin + queue.Add(A) + waiting++ -/datum/controller/garbage_collector/proc/process() - var/i - var/dels = 0 - for(i = 1, queue.len && i <= GC_COLLECTIONS_PER_TICK, i++) - Pop() - var/time_to_kill = world.time - GC_COLLECTION_TIMEOUT // Anything qdel() but not GC'd BEFORE this time needs to be manually del() - for(i = 1, destroyed.len && i <= GC_DEL_CHECK_PER_TICK, i++) - var/refID = destroyed[1] - var/GCd_at_time = destroyed[refID] - if(GCd_at_time > time_to_kill) -// testing("GC: [refID] not old enough, breaking at [world.time] for [GCd_at_time - time_to_kill] deciseconds until [GCd_at_time + GC_COLLECTION_TIMEOUT]") - break // Everything else is newer, skip them - var/atom/A = locate(refID) -// testing("GC: [refID] old enough to test: GCd_at_time: [GCd_at_time] time_to_kill: [time_to_kill] current: [world.time]") - if(A && A.gc_destroyed == GCd_at_time) // So if something else coincidently gets the same ref, it's not deleted by mistake - // Something's still referring to the qdel'd object. Kill it. - if(dels >= GC_FORCE_DEL_PER_TICK) -// testing("GC: Reached max force dels per tick [dels] vs [GC_FORCE_DEL_PER_TICK]") - break // Server's already pretty pounded, everything else can wait 2 seconds -// testing("GC: -- \ref[A] | [A.type] was unable to be garbage collected and was force del() --") + proc/Pop() + var/atom/movable/A = queue[1] + if(!A) return + if(!istype(A,/atom/movable)) + testing("GC given a [A.type].") del(A) - dels++ -// else -// testing("GC: [refID] properly GC'd at [world.time] with timeout [GCd_at_time]") - destroyed.Cut(1, 2) + return + for(var/vname in A.vars) + if(vname in uncollectable_vars) + continue + //testing("Unsetting [vname] in [A.type]!") + A.vars[vname]=null + A.loc=null + destroyed.Add("\ref[A]") + queue.Remove(A) + + proc/process() + for(var/i=0;i= world.time - GC_COLLECTION_TIMEOUT) + // Something's still referring to the qdel'd object. Kill it. + del(A) + destroyed.Remove(refID) /** * NEVER USE THIS FOR ANYTHING OTHER THAN /atom/movable * OTHER TYPES CANNOT BE QDEL'D BECAUSE THEIR LOC IS LOCKED OR THEY DON'T HAVE ONE. -* While I'm leaving the above comment in since /atoms cannot be garbage collected, datums and lists can be garbage collected just fine. -* Read the DM guide on it. Hit f1 and search for "garbage collection" */ /proc/qdel(var/atom/movable/A) - if(!A) - return + if(!A) return if(!istype(A)) warning("qdel() passed object of type [A.type]. qdel() can only handle /atom/movable types.") del(A)