-
Notifications
You must be signed in to change notification settings - Fork 758
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Finalizers are not run consistently / regularly, resulting in memory leak behavior. #4288
Comments
Changed the title, as this bug appears more broad, and affects some or all objects with finalizers. Some more cases that can easily repro:
There are two problems that may be at fault here:
My observations:
Remaining questions:
|
Is this only related to Qt? While doing some benchmarking on stuff that merely created Routines, I've noticed regular sclang crashes and slowdown occurring (before the crashes), presumably due to GC pressure. The kind of testing I was doing. After about a dozen of those in a row sclang was usually gone. Actually with some others it crashed even faster (fewer runs needed, probably because more Routine-creating reps in the actual bench).
|
Just wanted to float an alternative idea... what I have been able to get working is a wrapper around I've got a working branch but here is the gist... Create a new type of obj (omitting all the registering code, but importantly a new class is made). struct PyrRCResource : public PyrObjectHdr {
std::shared_ptr<void> ptr;
}; When objects are recycled in PyrObject* obj = (PyrObject*)gcs->mFree;
if (!IsMarker(obj)) {
// from free list
gcs->mFree = obj->next;
assert(obj->obj_sizeclass == sizeclass);
if (obj->classptr == class_rc_resource) {
std::cout << "freeing a rc_resouce\n";
auto resource = reinterpret_cast<PyrRCResource*>(obj);
std::destroy_at(resource); // calls destructor
} New PyrRCResource* newPyrRCResource(class PyrGC* gc, std::shared_ptr<void> ptr) {
constexpr auto sz = sizeof(std::shared_ptr<void>);
PyrRCResource* obj = gc == nullptr
? (PyrRCResource*)PyrGC::NewPermanent(sz, 0, obj_rc_resource)
: (PyrRCResource*) gc->New(sz, 0, obj_rc_resource, true);
obj->classptr = class_rc_resource;
obj->size = 0;
new (&obj->ptr) std::shared_ptr<void>(ptr);
return obj;
} I've tested this with a little lifetime struct, printing when the constructor and destructor gets called, along with the total in existence. This means the shared_ptr will be free'd at some point in the future when the free list get to them. ... if I spam them in a loop, my system will have about 250 of these alive at anyone time. No segfaults or double frees so far, but I've still got copying to sort out, but that should be easy (fingers crossed). |
A few issues here, if I'm understanding your proposal correctly:
This only frees resources when a new object is allocated in the slot, if I'm reading it correctly - NOT when the original object is destroyed. So the resources are leaked until you re-use that slot in the allocation pool, which will be in the future / could easily be never. If we want to free resources, why not do this when the object is freed rather than on the next allocation? I'm also not sure what kinds of guarantees we have that If the goal is to free some non-sclang resources when an object is destroyed, we already have a mechanism for this - Finalizers, they just seem partly broken :) Another consideration here:
I have an intuition that option #2 is the best one, since it keeps things working within the same system (SuperColliders GC and alloc pool) as much as possible - and, I've seen this exact mechanism for tracking lifetime when interfacing with outside systems in other scripting languages, which is a clue that it may solve some non-obvious problems. We have three or four different ways that external resourecs are tracked in sclang - there's some very worthy clean-up that could be done here that would I'm sure fix a bunch of bugs and ugly code. But I think first we need to figure out if we have finalizer problems and fix them. |
@scztt thank you for this! Yes you're right I didn't really consider that the memory might never be recycle, duh! I thought this might be cleaner because I spent quite a while trying to find the issue with finalizers and qt and couldn't. There was the double free issue when copying (the mess I suggested was supposed to address that), and another issue that I couldn't pin down. Your second suggestion there seems really clean and simple! |
Environment
Steps to reproduce
here is code that causes a memory leak:
here is a python script (3.7+) to monitory changes in memory usage over time for sclang:
The text was updated successfully, but these errors were encountered: