coll, objects and free method
Sorry for the machine-gun posting.
I’m having a quite serious problem with coll dealing with A_OBJ atoms.
The thing is, it looks like coll in certains occasions (e.g., I duplicate the coll) tries to free the objects whose pointers it has stored. But most of the times those objects have already been freed, and this results either in a "freeobject: bad object" in the Max window (small problem), or a Max crash (big problem), or even a computer crash (huge problem).
Of course it doesn’t make much sense to me to store the objects in a coll; but it’s a possible patching mistake, and it should not have devastating consequences. Moreover, while I have experienced this problem with coll, I fear that other object might have the same behavior.
My question is: is there a way to prevent coll from freeing the object? E.g., is there a flag I can set somewhere saying that my class must not be freed? In this case, I could free it only when I need, by "manually" calling its former free method and then freeing the memory taken by the object… does this make sense?
In general you should not be passing A_OBJ atoms in a max patcher, or storing them in a coll. There is essentially zero support for these atoms in standard box objects. We use hashed symbolic names for Jitter matrices for this reason.
That said, there is an essentially undocumented API for object_retain(t_object *x), and object_release(t_object *x) for object reference counting similar to Obj C. It’s up to you to ensure that there will be no memory leaks, and there’s no guarantee that coll might reference said object after you’ve freed said object, since coll will not call object_retain(). Use them at your own risk.
Or better yet, register the object in a namespace via object_register, and send the object name around the patcher, resolving by client objects with object_findregistered(). This way no other objects will be using or referencing the A_OBJ directly except the ones you are writing.
This lets you safely use useful box classes like pack, zl, coll, etc. with your symbolic object references. If your object disappears while any of them still refer to said reference, it won’t be locatable from object_findregistered().
However, internal to your class, I thought you might also have a use for object_retain/release. For example one of your recent posts that showed creating a temporary atom array could have been made a little simpler with object_retain/release.
In fact, because of the potentially great number of instances of my class, I don’t want to use symbols for naming or binding them – I fear they might clog up the symbol table. But I can do something not too different with numeric keys – I just need to set up a hash-table-like thing in order to deal with them, and then I can harmlessly pass them in the patcher as regular A_LONGs.
Some questions about object_retain/release, which look very useful to me:
1- are they thread-safe, or should I put a lock around their calls instead?
2- when an instance of an object is created, is its reference count automatically set to 1, or should I do it manually?
3- What happens if I call object_free() on a retained object? I.e., is object_free() aware of reference counting? (I guess 2 and 3 are mutually exclusive)
Thank you very much, as always
As for not bloating the symbol pool, you can use symbol_unique(), which after 10k symbols (@30 bytes each), will start reusing symbols from the unique symbol pool, so no further bloat than ~300k per application launch.
As for object_retain/release():
1. Yes, they are threadsafe.
2. Yes, the refcount is by default 1.
3. object_free decrements the count, as does object_release(). If the count is zero, the object is actually freed, otherwise it lingers in memory.
Hope this helps.
aah, I didn’t know about this thing of symbol_unique()
last questions about the reference counting system:
1. what is the actual difference between object_free and object_release, if both decrement the count and dispose the object when the count is 0?
2. is there a way to know the refcount of an object, for debugging?
1. The details are subtle. I would simply match object_new() (or other constructor) with object_free() and object_retain() with object_release().
Essentially, object_release() may not free an object if object_retain() has never been called. It is dependent on some special extra object info which we allocate if certain extended features are being used. object_retain() forces this to happen, but other things like registering an object, adding object specific attributes, etc. can do this as well.
In future versions, we could make object_release() free even in the absence of calling object_retain() first, but such a situation hasn’t been required by our internal usage.
2. Unfortunately, there is currently no way to get the reference count. We can consider this for the future, but for now, you’ll need to manage this elsewhere somehow.