-
Notifications
You must be signed in to change notification settings - Fork 57
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
How do you not cause memory leaks? #117
Comments
Returning an Also, it's quite confusing that you're using both To answer your specific question, I think you're missing a release af Shameless plug: In |
Thanks so much for your help @madsmtm
Do you mean most of the msg_send! e.g.
|
I pinpointed this is the first expression (the others following it also likely memory leak as well) causes a memory leak, but I wasn't able to figure how to stop it from occurring
Tried following with no success
With the following attempts on all 3 variants to stop the memory leak, no success
b)
c)
|
I think the last code you wrote, option c), should be correct: Since you've wrapped everything in an autorelease pool, the object's retain count should drop fully to zero once the autorelease pool drains. So just to be clear, I think your code should look something like: objc::rc::autoreleasepool(|| {
let ns_workspace_obj = unsafe {
let obj: *mut Object = msg_send![class!(NSWorkspace), alloc];
let obj: *mut Object = msg_send![obj, init];
Id::from_retained_ptr(obj) // `init` returns a retained instance
};
let path: Id<Object> = unsafe {
Id::from_retained_ptr(NSString::alloc(nil).init_str(path)) // `init` returns a retained instance
};
let ns_image: Id<Object> = unsafe {
Id::from_ptr(msg_send![ns_workspace_obj, iconForFile: &*path]) // `iconForFile` returns an autoreleased instance
};
let foundation_ns_data: Id<Object> = unsafe {
// `TIFFRepresentationUsingCompression:factor:` returns an autoreleased instance
Id::from_ptr(msg_send![ns_image, TIFFRepresentationUsingCompression: 6usize factor: 90.0f32])
};
// ...
}) (Here I've also fixed things like using the correct types in |
Wow @madsmtm afaics this seems to completely fix the leak.
I had not been wrapping the code in autoreleasepool Without this sample I had honestly resorted to a new cursed option 4) where I created a rust bin/executable to wrap the snippet in, which was freeing memory each time the executable finishes/ends 😅 |
No problem! As a teaser, in madsmtm/objc2#264 I'm building a new crate which has automatically generated bindings, and automatic memory management, allowing you to just do: use objc2::rc::autoreleasepool;
use icrate::Foundation::NSString;
use icrate::AppKit::NSWorkspace;
autoreleasepool(|| {
let ns_workspace_obj = unsafe { NSWorkspace::new() };
let path = NSString::from_str(path);
let ns_image = unsafe { ns_workspace_obj.iconForFile(&path) };
let foundation_ns_data = unsafe { ns_image.TIFFRepresentationUsingCompression_factor(6, 90.0) };
// ...
}) |
Hey there, @madsmtm. I've been reading through this issue over the last couple days and had a question if you don't mind. Are there headers somewhere documenting that specific methods return objects that are autoreleased (and hence require some autorelease pool), is this something you determined via a side-channel, or are you working off a broad interpretation of the autorelease documentation which notes that all detached or POSIX threads must handle their own pools if interacting with Cocoa APIs? |
It's all documented in https://clang.llvm.org/docs/AutomaticReferenceCounting.html. In short, whether something returns an autoreleased object vs. an owned object depends on the method name. I can elaborate if you want, but I suspect that link was what you were missing ;) |
I went through a mostly-complete read of that document (skimmed over some seemingly-unrelated parts) but I didn't see anything obvious about method names and release semantics. The only thing that looked like it may be it was Related result types. Is that what you were referencing as well? Either way, I would appreciate the elaboration if the rest of my analysis is off.
Assuming this is the right part, does this mean that since Rust code is not participating in ARC most |
He's referring to the section on method families: https://clang.llvm.org/docs/AutomaticReferenceCounting.html#arc-method-families
aka those methods return objects with a +1 retain count, meaning you need not retain them, and you are responsible for releasing them. All other methods return objects with a +0 retain count (potentially meaning they have been autoreleased), so if you want to ensure they stick around, you need to retain them yourself (and therefore also release them when you are done with them). |
I'm using the objc crate to get the icon/image of a macos .app file.
But my following snippet leaks memory. I am fairly certain it is this snippet because if I replace the snippet with a String of b64 of the same image, no memory leak occurs.
Does this snippet use the objc crate in a wrong way? I suspect I'm not seeing something obvious in the docs.
How can I prevent this snippet from causing memory leaks?
I've tried using various expressions of
let _: () = unsafe { msg_send![some_object, release] };
to release memory, but I get segmentation faults and rarely bus faults (for context this snippet is run in multithreaded env, perhaps contributing). Should the snippet be usingrelease
, and wrapping this snippet in something like a mutex so it can only be run by 1 thread at a time?The text was updated successfully, but these errors were encountered: