-
-
Notifications
You must be signed in to change notification settings - Fork 158
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
Provide and document @autoreleasepool block equivalent #12
Comments
This is great, thanks again. I like your suggested API starting point. |
Here is an alternate Go API: the function which allocates returns the function which deallocates.
|
It worked! I like this one better. What else we got |
I considered returning a function, the problem I have with that is a double paren defer doesn't seem like a common idiom in Go and it may be easier to forget or get confused about the second parens. |
If you're already allocating a closure, you can also do this to mirror the C structure:
All else the same my intuition is involving a closure may be slower in both cases. |
what does @bradfitz think of double parens? obviously you can avoid by assignment first, and its something that should only be done once so it seems silly to optimize too hard for convenience. closure is interesting too. |
FWIW it's more correct to use autoreleasepools often, not rarely. You'd put this near the FFI boundary or around iterations of your Go event loop, not just one outside the whole program. (One autoreleasepool outside the whole program does nothing for leaks, as it won't release any objects until your program exits anyway.)
I'm also now concerned about how Go thread scheduling will impact this. I bet autoreleasepool is thread local, so it's probably unsound without LockOSThread in the loop as well (when a Goroutine hops OS threads, it will lose its autoreleasepool, or it might even migrate to a thread with a pool with a different lifetime and double free or something) |
And do I understand it correctly it only applies to objects that are sent the |
Yes, but you shouldn't really autorelease objects yourself, as that's very foreign to Go memory management. The reason to use an autoreleasepool in modern objc is to prevent objects that Cocoa itself autoreleases inside API calls from being leaked (and it does that all the time). It's basically an FFI boundary issue, you shouldn't cross the boundary unless you're in an autoreleasepool. I think for your own objects, the best approach is probably |
@lunixbochs thank you for explaining. can you expand on the setfinalizer example? it sounds like i will need to document this. |
Here you call Alloc and return, so the "caller owns" the resulting object and must eventually Release it: https://github.com/progrium/macdriver/blob/main/cocoa/NSImage.go#L32-L34
Many objc APIs also return caller owned data, such as You can opt into the Go GC instead by doing something like this (needs further work as GC example doesn't return anything, but it's the general idea)
This means instead of:
You'd just do this:
Then the Go GC will automatically release objects when they have no references remaining. However it does look like you're currently passing objects as structs by value (containing a uintptr), which probably means the Go GC isn't involved. To fix that you'd need to use pointer types. Using the Go GC to manage objc lifetimes would be more memory safe than the current system. The current setup makes use after free and double free trivial, which IMO defeats a lot of the purpose of using Go in the first place. This is off topic from this issue, it's probably worth discussing in a new issue if you're interested. |
Yes! Would love a new thread on that idea, it sounds right. |
It would be hugely helpful if somebody could write a test that will fail until a solution for this is merged. |
I wonder if it would be reasonable for
|
Implements `Autorelease(func())` to run the body with an active autoreleasepool. Existing calls to `NSAutoreleasePool` have been replaced and wrapped with this block helper. Fixes #12
From this thread: https://news.ycombinator.com/item?id=26028441
If you call into Cocoa APIs from foreign threads without an @autoreleasepool block active, the APIs will leak memory.
https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmAutoreleasePools.html
This StackOverflow answer suggests the @autoreleasepool block is implemented by generating calls to these objc runtime functions:
Here's an example of how you might provide the API: https://play.golang.org/p/dljXN3BdEGr
I also suggest prominently documenting this once it is implemented, as any long running app calling into Cocoa APIs will leak without it.
The text was updated successfully, but these errors were encountered: