Hacker News new | past | comments | ask | show | jobs | submit login

I don't see an @autoreleasepool anywhere in the source, which I believe means calling some AppKit APIs from Go-managed threads will silently leak memory (due to memory allocated internally by the APIs that will never get released).

In my own projects, I had to wrap calls from foreign threads into AppKit APIs with an @autoreleasepool {} block or my app would leak memory. [1]

[1] https://developer.apple.com/library/archive/documentation/Co...




I thought I wrapped NSAutoreleasePool but maybe I just used it directly dynamically. If something is not wrapped in the source that doesn't mean you can't use it. objc.Get("NSAutoreleasePool").Alloc().Init()

Unfortunately I can afford some leaks at the moment, so if that's critical to anybody else and I'm doing something wrong just submit a PR


Ah, I don't just mean the class, I mean you need to have an autoreleasepool block active before calling into AppKit otherwise you can leak memory on every call. It doesn't look like you're using pools yet, or documenting that users of your library should use them.

See here: https://developer.apple.com/library/archive/documentation/Co...

> Cocoa always expects code to be executed within an autorelease pool block, otherwise autoreleased objects do not get released and your application leaks memory


I guess I will look into this as that really sounds like syntactic sugar for something more basic. Like using the class.

I have a hard time keeping up with their changes but you might be right: https://developer.apple.com/documentation/foundation/nsautor...

Oddly it says you cannot use them directly, but later implies maybe they are just less efficient. It would be nice if somebody made an issue for this.


The page you linked is not actually ambiguous, though perhaps a bit tricky to read. It says:

1. If you're compiling Objective C in ARC mode, you can't use NSAutoreleasePool directly, and must instead use @autoreleasepool.

2. In manual reference counting mode you can use either NSAutoreleasePool or @autoreleasepool, but the latter has lower overhead. (This may matter if e.g. you're draining the autorelease pool on every iteration of a loop to reduce memory spikes.)

Under the hood -- at least on the version I disassembled -- NSAutoreleasePool's -init and -release methods wrap the CoreFoundation CFAutoreleasePoolPush and CFAutoreleasePoolPop functions, which in turn call the runtime's objc_autoreleasePoolPush and objc_autoreleasePoolPop functions, which are the things that @autoreleasepool will cause the compiler to emit directly.


This answer says the block is more efficient than manually managing NSAutoreleasePool objects: https://stackoverflow.com/a/12448176

This answer looks like a better overview of what the runtime is doing: https://stackoverflow.com/a/21010442

The @autoreleasepool block seems equivalent to this:

    ctx = _objc_autoreleasePoolPush()
    defer _objc_autoreleasePoolPop(ctx)
You could maybe provide sugar for it like this: https://play.golang.org/p/dljXN3BdEGr


The implementation of your "sugar" can be shortened:

https://play.golang.org/p/8v4EL2B_c_t


Awesome, can you throw into an issue?



wow, thanks!


Keep in mind that the reason the `@autorelease` syntax is faster is primarily due to ARC optimizations (which don't apply here, since you're not using ARC).

Calling the `_objc_autoreleasePoolXX` functions are still likely to be faster than the NSAutoreleasePool objects, but only because you're avoiding the Objective-C message sends.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: