-
Notifications
You must be signed in to change notification settings - Fork 516
Garbage, qdel, and Destroy
A new garbage collector has been introduced with SMC, this comes with new features for Destroy() as well as an enforced requirement to return parent in Destroy().
The basic purpose of Destroy()
is to clean up all references to the source object and to then return a garbage collection hint (generally done by returning the parent). Most of the time this should be done by putting return ..()
at the end of your Destroy()
proc, though it generally does not matter. If you do not return parent, you must still call it & you must return a hint. If applicable, Destroy()
should also queue the deletion of child objects that are attached to the main object. Destroy()
should never transform an object or create more objects (like mechs do).
This is how most Destroy() procs should generally be structured:
/obj/mything/Destroy()
some_global_list_of_mythings -= src
return ..()
The garbage collector also understands deletion hints. Most of the time you should not need these, but they can be used when objects require special deletion behavior, such as hard-deletion or deletion immortality. These are the hints that are understood:
Hint | Behavior |
---|---|
QDEL_HINT_QUEUE |
Handle deletion normally. This is the default, you generally shouldn't need to manually specify this. |
QDEL_HINT_LETMELIVE |
Do not delete on non-forced qdel. If you use this hint, you must respect force deletions. The GC will ignore this hint and complain if it is returned on force-delete. |
QDEL_HINT_IWILLGC |
This object will handle GC itself and the GC should leave it alone. Functionally the same as LETMELIVE. Returning this hint will cause the GC to not check up on it to see if it deleted, and as such it will not be queued & use GC resources. Objects that use this hint do not need to obey force, but this hint should not be used to make objects that are immortal to force-delete. |
QDEL_HINT_HARDDEL |
Hard-delete this object instead of attempting to GC it. Garbage will wait until the next tick where it has free processing time to delete. Can be expensive, avoid usage if possible. |
QDEL_HINT_HARDDEL_NOW |
Hard-deletes this object ASAP (within the same stack as qdel). Works even if the garbage collector is not running or is non-responsive. Can be expensive, avoid usage if possible. |
QDEL_HINT_FINDREFERENCE |
Functionally identical to QDEL_HINT_QUEUE , except the GC will run find-references on del if TESTING is defined. In a non-testing compile environment, has no special behavior. Be warned that find-references can take upwards of 10 minutes to run, during which it will cause a lot of lag. |
To use a hint, return it instead of returning parent. You must still call parent. If you're using QDEL_HINT_LETMELIVE
, you must respect the force parameter. If you do not respect the force parameter, the GC will delete you anyways on force delete and make noise in server logs. Admin-delete uses force-delete.
Example of a Destroy() with a hint:
/obj/mything/myotherthing/Destroy()
some_global_list_of_myotherthings -= src
..()
return QDEL_HINT_HARDDEL
Example of a Destroy() with a force-respecting hint:
/obj/mything/myotherotherthing/Destroy(force = FALSE)
if (!force)
world << "Something tried to delete [src]!"
return QDEL_HINT_LETMELIVE
// force-deletion
world << "[src] force-deleted."
return ..()
qdel()
has a new optional parameter that follows the thing-to-be-deleted: force
. If force is TRUE
, the object is force-deleted. Force delete behavior is dependent on the object being deleted, but it generally will delete objects that return immortality hints such as LETMELIVE
and sometimes (implementation dependent) cause IWILLGC
objects to instead return QUEUE
so that their deletion is confirmed.
Objects that return a QUEUE
hint are added to SSgarbage's queue. SSgarbage will give BYOND 5 minutes (by default) to GC the object before it intervenes. If an object has not been GC'd by the timeout period, SSgarbage will assume the object is not going to GC and will hard-delete it when it has spare CPU time. SSgarbage can only run one hard-delete per garbage tick, and hard-deletions may postpone further garbage ticks depending on how expensive the hard-delete was.
There are three types of datum references in this codebase: hard refs (just a normal BYOND var), soft refs (a naked locate()able string), and weak refs (a /datum/weakref
). Hard refs will block GC, but soft refs and weak refs will not.
In terms of speed, hard-refs are faster than soft-refs which are faster than weak-refs.
Hard-refs are the only ones that can be used to access variables on an object, but the other two can be converted into hard-refs.
These are strings generated by SOFTREF(datum)
or "\ref[datum]"
. They can be fed to locate()
to convert them into a hard ref, but it is not guaranteed that they will still point at the same object they did when they were created - the object must be verified before use.
var/datum/mydatum = new
var/myref = SOFTREF(mydatum)
mydatum = null
var/datum/the_datum = locate(myref)
if (istype(the_datum))
world << "Datum is valid!
else
world << "Datum is invalid!"
These are instances of /datum/weakref
, as generated by the WEAKREF(datum)
macro. /datum/weakref
has a call resolve()
which will return a hard ref to the original datum if it still exists and hasn't been marked for del by the GC, or null otherwise. These will handle validation for you, so a datum returned by resolve()
is guaranteed to be the same datum originally given to WEAKREF(datum)
.
Note: Do not delete/qdelete the weakref datum! It will automatically be cleaned up when it is no longer in use.
var/datum/mydatum = new
var/datum/weakref/myref = WEAKREF(mydatum)
mydatum = null
var/datum/the_datum = myref.resolve()
if (the_datum)
world << "Datum is valid!"
else
world << "Datum is invalid!"
A collection of standards and guidelines applied to the codebase.
Documentation regarding common APIs which speed up feature implementation and should be known by all coders.
- Atom Initialization
- Garbage, Queued Deletion, and Destroy
- Callbacks
- Timers
- Lazy Lists
- Overlays
- Processing APIs
- Common Helpers
- Global Listeners
- Singletons
Documentation for less used APIs that are not often needed.
Documentation regarding our implementation of StonedMC (SMC).
Decrepit or unused systems.
- Dynamic Maps (Not to be confused with the newer away mission implementation.)