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
[SR-5463] Unnecessary autoreleases when working with FileHandle and Data #3832
Comments
I am not certain we can change the behavior of the objective-c classes since it would mean a runtime behavior difference. Does this particularly express here because the ARC optimization of autorelease return values is not happening? Or is it the lifespan caused by an autorelease caused by swift? It definitely needs more detailed traces to isolate the offenders. |
Also: what other cases are causing this failure? I doubt it is just FileHandle. |
I assumed it was coming from somewhere inside the MRC code of the frameworks, which is why I pitched adding autoreleasepool wrappers to the overlay. I was asked to file a bug report instead, and so here we are. Looking at these traces, we might be getting a little of both: (lldb) bt
* thread #​1, queue = 'com.apple.main-thread', stop reason = breakpoint 2.27
frame #​0: 0x00007fffa7664a50 libobjc.A.dylib`-[NSObject autorelease]
* frame #​1: 0x000000010000202b AutoreleaseFool`@nonobjc FileHandle.__allocating_init(forReadingFrom:) at main.swift:0
frame #​2: 0x0000000100001a5f AutoreleaseFool`main at main.swift:14
frame #​3: 0x00007fffa7f53235 libdyld.dylib`start + 1 (lldb) bt
* thread #​1, queue = 'com.apple.main-thread', stop reason = breakpoint 2.27
* frame #​0: 0x00007fffa7664a50 libobjc.A.dylib`-[NSObject autorelease]
frame #​1: 0x00007fff9425f829 Foundation`-[NSConcreteFileHandle readDataOfLength:] + 639
frame #​2: 0x0000000100001ae8 AutoreleaseFool`main at main.swift:18
frame #​3: 0x00007fffa7f53235 libdyld.dylib`start + 1 (lldb) bt
* thread #​1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
frame #​0: 0x00007fffa7665d70 libobjc.A.dylib`objc_autorelease
* frame #​1: 0x00000001000587ed AutoreleaseFool`Foundation.Data.withUnsafeBytes<A, B>((Swift.UnsafePointer<B>) throws -> A) throws -> A + 141
frame #​2: 0x0000000100001bd0 AutoreleaseFool`main at main.swift:22
frame #​3: 0x00007fffa7f53235 libdyld.dylib`start + 1 |
I'm sure that there are many Cocoa classes that do this; however, FileHandle and Data were voted by their respective high school classes as most likely to chew through gigabytes of data in a loop, so I figured they'd be good starting points. |
The access autoreleases are almost certainly tied to the use of NS_RETURNS_INNER_POINTER in NSData, not some general thing relating to the use of ObjC classes. We are likely already tracking the creation autorelease as rdar://27528234, but it never hurts to have extra test cases. |
Attachment: Download
Environment
Xcode 9 beta 3
Additional Detail from JIRA
md5: 099e1e81fcb28efa04895a4713447b19
Issue Description:
FileHandle's readData(ofLength:), as well as Data's withUnsafeBytes(), generate autoreleases on systems that feature the Objective-C bridge. If these are used in a loop to read a very large file, this can quickly consume all of the system's memory and render the machine unresponsive, for reasons that are not clear to a new developer unfamiliar with Objective-C and its pitfalls. It's also annoying to work around since an @autoreleasepool attribute can't simply be tacked onto a loop; instead, you must individually wrap every call that creates or accesses the data, or else flow control constructs such as 'break' and 'continue' become unavailable.
See this thread for more details:
https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20170710/038085.html
I have attached three test cases:
"AutoreleaseFool" - reads a megabyte at a time from /dev/random using FileHandle. You can watch the program's memory usage creep upward as it runs.
"Otto von Releasepool" - This time the creation of the data is wrapped in an autorelease pool, but the data is then autoreleased while accessing it.
"No P in Our AutoreleaseOol" - This time both creation and access are wrapped in autorelease pools, and the program's memory usage finally behaves as one would expect.
The text was updated successfully, but these errors were encountered: