I've come across a memory leak in Swift on the Mac. I'm creating a buffer for a calculation on the GPU using Metal. The storage created for these is automatically deleted when they are out of scope UNLESS I bind the contents to memory.
In this case, the memory is not deleted even when both the buffer and the bound pointer are out of scope.
I tried manually deallocating the buffer, but this fails since the memory was not allocated using malloc.
Is there a way to manage this memory to avoid a leak, or is this a bug in Swift on the Mac?
Any other thoughts?
Thank you very much,
Colin
let intensityBuff = myGPUData.device?.makeBuffer(length: MemoryLayout<Float>.stride * Int(myStars.nstars * myStars.npatch * myStars.npatch, options: .storageModeShared)
let intensityPointer = intensityBuff?.contents().bindMemory(to: Float.self, capacity: MemoryLayout<Float>.stride * Int(myStars.nstars * myStars.npatch * myStars.npatch))
Metal buffers need to have the flag MTLPurgeableState.empty set to indicate they can be cleared out of memory after you are done using them. For example:
intensityBuff!.setPurgeableState(MTLPurgeableState.empty)
It turns out that the issue is that not all of Apple's code has been ported to Swift - the bindMemory command is actually written in Objective-C.
For these functions, ARC doesn't work automatically - instead you need to include the code within an autoreleasepool block e.g.
autorelease {
code with bindMemory statement in
}
I haven't tested out the MTLPurgeableState.empty suggested above by Nate (thank you for that suggestion), since the autorelease works fine.
And of course, Apple doesn't tell you which of the functions are Objective-C based - at least not that I could find!
Related
With the Xcode Profiler I have just spotted a not really necessary memory peak on JSON decoding. Apparently it's a known issue and I should wrap the call in an autoreleasepool which helped:
//extension..
var jsonData: Data? {
return autoreleasepool{ try? JSONSerialization.data(withJSONObject: self, options: []) }
}
I found another few big chunks of allocations that were not really needed so I applied my newly-learned trick to other code as well, such as the following:
var protoArray = [Proto_Bit]()
for bit in data {
autoreleasepool{
if let str = bit.toJSONString() {
if let proto = try? Proto_Bit(jsonString: str) {
protoArray.append(proto)
}
}
}
}
Now, before I wrap every single instruction of my code (or at least wherever I see fit) in this autoreleasepool thing, I would like to ask if there are any risks or drawbacks associated to it.
With these two wraps I was able to reduce my peak memory consumption from 500mb to 170mb. I am aware that Swift also does these kinds of things behind the scenes and probably has some guards in place however I would rather be safe than sorry.
does autoreleasepool come with a CPU overhead? If it is 5% I would be okay with that since it sounds like a good tradeoff, if it's more I would have to investigate
can I mess up anything using autoreleasepool? Null pointers, thread locking etc. since the block structure looks a bit scary.. or is this just telling the hardware "at the end of the bracket clean up and close the door behind you" without affecting other objects?
Autorelease Pools are a mechanism which comes from Objective-C for helping automate memory management and ensure that objects and resources are released "eventually", where that "eventually" comes when the pool is drained. i.e., an autorelease pool, once created on a thread, captures (retains) all objects which are -autoreleaseed while the pool is active — when the pool is drained, all of those objects are released. (Note that this is a Foundation feature in conjunction with the Objective-C runtime, and is not directly integrated with hardware: it's way, way higher-level than that.)
As a short-hand for managing autorelease pools directly (and avoiding creating NSAutoreleasePool instances directly), Objective-C introduced the #autoreleasepool language keyword, which effectively creates an autorelease pool at the beginning of the scope, and drains it at the end:
#autoreleasepool /* create an autorelease pool to capture autoreleased objects */ {
// ... do stuff ...
} /* release the autoreleasepool, and all objects that were in it */
Introducing autorelease pools manually in this way grants you more control over when autoreleased objects are effectively cleaned up: if you know that a block of code creates many autoreleased objects that really don't need to outlive that block of code, that may be a good candidate for wrapping up in an #autoreleasepool.
Autorelease pools pre-date ARC, which automates reference counting in a deterministic way, and its introduction made autorelease pools became largely unnecessary in most code: if an object can be deterministically retained and released, there's no need to rely on autoreleasing it "at some point". (And in fact, along with regular memory management calls like -retain and -release themselves, ARC will not allow you to call -autorelease on objects directly either.)
Swift, following the ARC memory management model, also does not rely on autoreleasing objects — all objects are deterministically released after their last usage. However: Swift does still need to interoperate with Objective-C code, and notable, not all Objective-C code (including a lot of code in, e.g., Foundation) uses ARC. Many internal Apple frameworks still use Objective-C's manual memory management, and thus still rely on autoreleased objects.
On platforms where Swift might need to interoperate with Objective-C code, no work needs to be explicitly done in order to allow autoreleased objects to eventually be released: every Swift application on Darwin platforms has at least one implicit autorelease pool at the root of the process which captures autoreleased objects. However, as you note: this "eventual" release of Objective-C objects might keep memory usage high until the pool is drained. To help alleviate that high memory usage, Swift has autoreleasepool { ... } (matching Objective-C's #autoreleasepool { ... }), which allows you to explicitly and eagerly capture those autoreleased objects, and free them at the end of the scope.
To answer your questions directly, but in reverse order:
Can I mess up anything using autoreleasepool? For correctly-written code, no. All you're doing is helping the Objective-C runtime clean up these objects a little bit earlier than it would otherwise. And it's critical to note: the objects will only be released by the pool — if their retain count is still positive after the pool releases them, they must still be in use somewhere, and will not be deallocated until that other owner holding on to the object also releases them.
Is it possible that the introduction of an autoreleasepool will cause some unexpected behavior to occur which didn't before? Absolutely. Incorrectly-written code could have accidentally worked due to the fact that an object was incidentally kept alive long enough to prevent unintentional behavior from occurring — and releasing the object sooner might trigger it. But, this is both unlikely (given the miniscule amount of actually manual memory management outside of Apple frameworks) and not something you can rely on: if the code misbehaves inside of a newly-introduced autoreleasepool, it wasn't correct to begin with, and could have backfired on you some other way.
Does autoreleasepool come with a CPU overhead? Yes, and it is likely vanishingly small compared to the actual work an application performs. But, that doesn't mean that sprinkling autoreleasepool all over the place will be useful:
Given the decreasing amount of autoreleased objects in a Swift project as increasing amounts of code transition away from Objective-C, it's becoming rarer to see large numbers of autoreleased objects which need to be eagerly cleaned up. You could sprinkle autoreleasepools everywhere, but it's entirely possible that those pools will be entirely empty, with nothing to clean up
autoreleasepools don't affect native Swift allocations: only Objective-C objects can be autoreleased, which means that for a good portion of Swift code, autoreleasepools are entirely wasted
So, when should you use autoreleasepools?
When you're working with code coming from Objective-C, which
You've measured to show that is contributing to high memory usage thanks to autoreleased objects, which
You've also measured are cleaned up appropriately by the introduction of an autoreleasepool
In other words, exactly what you've done here in your question. So, kudos.
However, try to avoid cargo-culting the insertion of autoreleasepools all over the place: it's highly unlikely to be effective without actual measurements and understanding what might be going on.
[An aside: how do you know when objects/code might be coming from Objective-C? You can't, very easily. A good rule of thumb is that many Apple frameworks are still written in Objective-C under the hood, or may at some layer return an Objective-C object bridged (or not) to Swift — so they may be a likely culprit to investigate if you've measured something actionable. 3rd-party libraries are also much less likely to contain Objective-C these days, but you may also have source access to them to confirm.]
Another note about optimizations and autoreleasepools: in general, you should not typically expect a Release configuration of a build to behave differently with regard to autoreleased objects as opposed to a Debug configuration.
Unlike ARC code (both in Swift and in Objective-C), where the compiler can insert memory management optimizations for code at compile time, autorelease pools are a runtime feature, and since any retain will necessarily keep an object instance alive, even a single insertion of an object into an autorelease pool will keep it alive until it is disposed of at runtime. So, even if the compiler can aggressively optimize the specific locations of retains and releases for most objects in a Release configurations, there's nothing to be done for an object that's autoreleased.
(Well, the ARC optimizer can do some amount of optimization around autoreleasing objects if it has enough visibility into all of the code using the object, the context of the autorelease pools it belongs to, etc., but this is usually very limited because the scope in which the object was originally -autoreleased is usually far from the scope in which the autorelease pool lives, by definition [otherwise it would be a candidate for regular memory management].)
I am using CoreML to remove the background in a given image and I have 2 major problems with it.
The model I embedded in my Xcode is DeepLabV3.mlmodel. This is the entire class that returns the final image: RemoveBackgroundCoreML_Final.swift which I just imported into my source code. It works well in terms of doing its job. However, I have a warning in this swift class at line 107:
let data = Data(buffer: UnsafeBufferPointer(start: &cubeRGB, count: cubeRGB.count))
Initialization of 'UnsafeMutableBufferPointer' results in a dangling buffer pointer
The worse case is, this line of the code crashes the production app according to my crash logs from the App Store for some devices, even though I myself don't experience any crash in the development environment.
This is how i call removeBackground method in above Swift class from my code:
let finalImage = image.removeBackground(returnResult: .finalImage)
Another issue is, above line returns finalImage but it also blocks the main thread in the app which has some UI animation just started to run previously to show some process (which I suspect, could be related to buffer pointer).
I hope anyone who has experience with CoreML or threading can help me and I too much appreciate it. Please ask, if further clarification needed. Thank you in advance.
Since you're not using cubeRGB after making the pointer to it, the Swift optimizer will deallocate it immediately afterwards. As this is an optimizer thing, you won't get this bug in debug mode, only in release mode.
Data(buffer:...) will make a copy of the array, so that's good. You just need to make the array stays alive until it's done copying. This can be done with withExtendedLifetime, something like:
let data = withExtendedLifetime(cubeRGB) {
return Data(buffer: UnsafeBufferPointer(start: &cubeRGB, count: cubeRGB.count))
}
I've probably got the syntax wrong but something like that.
I have an app written in swift which works fine initially, but throughout time the app gets sluggish. I have opened an instruments profiling session using the Allocation and Leaks profile.
What I have found is that the allocation increases dramatically, doing something that should only overwrite the current data.
The memory in question is in the group < non-object >
Opening this group gives hundreds of different allocations, with the responsible library all being libvDSP. So with this I can conclude it is a vDSP call that is not releasing the memory properly. However, double clicking on any of these does not present me with any code, but the raw language I do not understand.
The function that callas vDSP is wrapped like this:
func outOfPlaceComplexFourierTransform(
setup: FFTSetup,
resultSize:Int,
logSize: UInt,
direction: FourierTransformDirection) -> ComplexFloatArray {
let result = ComplexFloatArray.zeros(count:resultSize)
self.useAsDSPSplitComplex { selfPointer in
result.useAsDSPSplitComplex { resultPointer in
vDSP_fft_zop(
setup,
&selfPointer,
ComplexFloatArray.strideSize,
&resultPointer,
ComplexFloatArray.strideSize,
logSize,
direction.rawValue)
}
}
return result
}
This is called from another function:
var mags1 = ComplexFloatArray.zeros(count: measurement.windowedImpulse!.count)
mags1 = (measurement.windowedImpulse?.outOfPlaceComplexFourierTransform(setup: fftSetup, resultSize: mags1.count, logSize: UInt(logSize), direction: ComplexFloatArray.FourierTransformDirection(rawValue: 1)!))!
Within this function, mags1 is manipulated and overwrites an existing array. It was my understanding that mags1 would be deallocated once this function has finished, as it is only available inside this function.
This is the function that is called, many times per second at times. Any help would be appreciated, as what should only take 5mb, very quickly grows by two hundred megabytes in a couple of seconds.
Any pointers to either further investigate the source of the leak, or to properly deallocate this memory once finished would be appreciated.
I cannot believe I solved this so quickly after posting this. (I genuinely had several hours of pulling my hair out).
Not included in my code here, I was creating a new FFTSetup every time this was called. Obviously this is memory intensive, and it was not reusing this memory.
In instruments looking at the call tree I was able to see the function utilising this memory.
I got a memory leak when I detect with instrument. I don`t have so much experience about memory-management, so I can not figure out what is the possible cause for this problem, the memory leak is as below:
I want to know the possible reason about this kind of memory leak. Is some one who can give me some clues?
strdup uses malloc internally, so anything that has been strdup-ed has to be freed using free.
For example:
char *duplicate = strdup("abcdef");
...
free(duplicate);
strdup() is a library function, so you need to go back up the backtrace until you find a caller that's in your code. There you'll find a library call which is resulting in memory being allocated - it should have a corresponding freeing call elsewhere in your program.
(The freeing function is not necessarily a direct call to free() - for example if you call the getaddrinfo() library function the corresponding freeing function is freeaddrinfo()).
With reference to the question here.
The solutions provided in that thread, include:
Being smart about where and how many variables you declare, that would go on the stack.
Disable Guard Malloc if needed.
Also, in general:
3. Make sure you are releasing a variable you have actually allocated memory for!!
I have none of the above issues. There are very few stack-allocated variables that I use within functions, say 2-3 within each. But because the functions are called in a loop several times, it seems to trigger an exception.
And here's the kicker, this is not just happening for statically allocated variables, but stuff on the heap too! I'm getting the page errors on Auto-released declarations of NSNumber variables that I use a couple of inside the loop, as well as a dictionary that I juDIciously alloc and release within the scope of the function, every single time it's called.
So why is this happening, and why the heck are heap variables getting affected? I don't get it at all, please throw some light on this. :)
I'm on IOS5 with XCode 4.2, iPhone/iPad simulator.
Thanks!
Regards,
Dev
Edit: Sample code
- (void)doSomething {
NSInteger fun = 3;
NSInteger time = 4;
NSInteger overload = fun*time;
NSString *string = [NSString stringWithFormat:#"%d",overload];
NSObject *myCustomObject = [[NSObject alloc] init];
[myCustomDictionary setObject:myCustomObject forKey:string];
[myCustomObject release];
//myCustomDictionary is an iVar, alloced in the class's init method, and released in dealloc and not touched anywhere in between
}
//doSomething gets called several times through the course of execution as the state of the view changes, the user interacts with it etc, often 2-3 times during one state change.
The code is purposely vague, but at the same time, it is EXACTLY as simple as in the sample. As is the rest of the code in the entire project. Several functions, each doing a small amount of work, as nicely self contained memory-wise as this one.
I faced EXC_BAD_ACCESS issues before, and at that point had referred to this question. However in my case, I was not creating multiple variables on the stack within a loop, they were getting created repeatedly by a function which gets called several times through the course of the execution. Ideally, the variables should have just got destroyed at the end of function-scope. Not sure why that didn't happen.
Anyway, to resolve that and to prevent multiple allocations from happening, I ended up declaring my stack-allocated variables as all static. That is bad practice, but that's exactly what I had to do to get it working. And it was working until I ended up facing the issue AGAIN with the "doSomething" function.
So the difficulty in "doSomething", was that I did not have only stack-allocated variables getting created, but heap stuff too. So I first started getting EXC_BAD_ACCESS on the NSInteger variables, at which point I tried fixing it again, by declaring them as static. It worked, but now EXC_BAD_ACCESS started occurring on the auto-released variable and finally the custom-allocated variable - which is when I got stumped. I have been following all the rules of memory management, and I'm having stack AND heap variables fubaring all over me. If it was only heap stuff, or stack stuff inside a loop, I could understand there's a mistake SOMEwhere. But here, it's neither, these are perfectly innocent variables getting allocated on the stack inside ONE function that is NOT called in a loop, and regular auto-released variables that never ever get retains or releases thrown at them from another place in the code. What makes it all even worse, is that the failure points are random - not just in this function but practically every one that gets called several times through the course of execution of the project.
Edit2: Turns out, in this case, it's my fault. See my answer for details. Sorry for wasting people's time. :\
We can't really help you without seeing the whole stack trace.
EXC_BAD_ACCESS doesn't mean anything in order to troubleshoot we need to know what the exception is.
Based on my experience when you don't get a stack tarce it means you are double releasing. Zombies is the way to find your double release.
Go to: Product -> Profile and then select "Zombies" from the list.
Run the app and perform any task that causes the crash, if the problem is a double release a pop-up would appear. Select the arrow in the popup and it tells you exactly what object is being double released, and it shows you the retain cycle.
Without any code posted in your question, and seeing that you are using iOS 5 and Xcode 4.2 my best advice for you is, in Xcode, go to Edit>Refactor>Convert to Objective-C ARC and wave all your memory management headaches goodbye.
ARC does all the memory management for you. You do not need to retain, release or write dealloc methods. You don't have to worry about memory management in most cases. You will leave mysterious EXC_BAD_ACCESS crashes behind. The way it works is super efficient. The compiler puts in the retains and releases for you and then optimises. You never even have to see the code.
Ah geez I don't believe this.
The issues faced earlier with the stack-allocated NSInteger variables holds, but in this case, it was entirely my fault.
"doSomething" was part of a long chain of events, that, due to some silly negligence on my part, ends up looping a bunch of times, which is what, rightfully and as it should be, leads to the application running out of memory. Whether it's with the stack variables or with the malloced ones sitting on the heap, with an infinite loop, it's gonna crash one way or another. :)
So the crash is perfectly fair, just got confused in this case with a previous issue that turned out to be unrelated. :(
Sorry for wasting everybody's time.