I've been saying this to form a C array of CGPoint:
let arr = UnsafeMutablePointer<CGPoint>.allocate(capacity:4)
defer {
arr.deinitialize()
arr.deallocate(capacity:4)
}
arr[0] = CGPoint(x:0,y:0)
arr[1] = CGPoint(x:50,y:50)
arr[2] = CGPoint(x:50,y:50)
arr[3] = CGPoint(x:0,y:100)
Now (Swift 4.1 in the Xcode 9.3 beta) both deinitialize and deallocate(capacity:) are deprecated. It looks like what I'm supposed to say now might be:
defer {
arr.deinitialize(count:4)
arr.deallocate()
}
Is that right?
Yes, that is part of SE-0184 Unsafe[Mutable][Raw][Buffer]Pointer: add missing methods, adjust existing labels for clarity, and remove deallocation size,
which has been implemented in Swift 4.1.
In particular:
Removing capacity from deallocate(capacity:) will end the confusion over what deallocate() does, making it obvious that deallocate() will free the entire memory block at self, just as if free() were called on it.
The old deallocate(capacity:) method should be marked as deprecated and eventually removed since it currently encourages dangerously incorrect code.
Related
Was trying to fix a 300MB memory-leak, and after finding leak-reason;
(Which was calls to NSString's stringFromUTF8String:, from C++ thread (without #autoreleasepool-block wrapper))
I edited the code, to enforce reference-counting (instead of auto-release), something like below:
public func withNSString(
_ chars: UnsafePointer<Int8>,
_ callback: (NSString) -> Void
) {
let result: NSString = NSString(utf8String: chars)!;
callback(result);
}
As personal policy, with a Unit-Test, like:
import Foundation
import XCTest
#testable import MyApp
class AppTest: XCTestCase {
func testWithNSString_hasNoMemoryLeak() {
weak var weakRef: NSString? = nil
autoreleasepool {
let chars = ("some data" as NSString).utf8String!;
withNSString(chars, { strongRef in
weakRef = strongRef;
XCTAssertNotNil(weakRef);
})
// Checks if reference-counting is used.
XCTAssertNil(weakRef); // Fails, so no reference-counting.
}
// Checks if autoreleased.
XCTAssertNil(weakRef); // Fails, OMG! what is this?
}
}
But now, not even auto-release seems to work anymore (-_- )
Why does last XCTAssertNil call fail?
(In other words, how can I fix memory-leaks?)
The problem is that you're using a very short string. It's getting inlined onto the stack, so it's not released until the entire stack frame goes out of scope. If you made the string a little bit longer (2 characters longer), this would behave the way you expect. This is an implementation detail, of course, and could change due to different versions of the compiler, different versions of the OS, different optimization settings, or different architectures.
Keep in mind that testing this kind of thing with static strings of any kind can be tricky, since static strings are placed into the binary. So if the compiler notices that you've indirectly made a pointer to a static string, then it might optimize out the indirection and not release it.
In none of these cases is there a memory leak, though. Your memory leak is more likely in the calling code of withNSString. I would mostly suspect that you're not properly dealing with the bytes passed as chars. We would need to see more about why you think there's a leak to evaluate that. (Foundation also has some small leaks, and Instruments has false positives on leaks, so if you're chasing an allocation that is smaller than 50 bytes and doesn't recur on every operation, you probably are chasing ghosts.)
Note that this is a bit dangerous:
let chars = ("some data" as NSString).utf8String!
withNSString(chars, { strongRef in
The utf8String inner pointer is not promised to live longer than the NSString, and Swift is free to destroy objects after their last reference (which may be before they go out of scope). As the docs note:
This C string is a pointer to a structure inside the string object, which may have a lifetime shorter than the string object and will certainly not have a longer lifetime. Therefore, you should copy the C string if it needs to be stored outside of the memory context in which you use this property.
In this case the object is a constant string, which is in the binary and cannot be destroyed. But in more general cases this is is a classic cause of crashes. I would highly recommend moving away from the NSString interfaces and using String. It offers utf8CString, which returns a proper ContinguousArray, which is much safer.
let chars = "some data".utf8CString
chars.withUnsafeBufferPointer { buffer in
withNSString(buffer.baseAddress!, { strongRef in
weakRef = strongRef;
XCTAssertNotNil(weakRef);
})
}
withUnsafeBufferPointer ensures that chars cannot be destroyed before the block completes.
You can also ensure the lifetime of the string if needed (this is mostly useful for fixing older code you don't want to rewrite in safer ways):
let string = "some data"
withExtendedLifetime(string) {
let chars = string.utf8CString
chars.withUnsafeBufferPointer { buffer in
withNSString(buffer.baseAddress!, { strongRef in
weakRef = strongRef;
XCTAssertNotNil(weakRef);
})
}
}
On page 17 of this WWDC14 presentation, it says
Working with Objective-C? Still have to manage autorelease pools
autoreleasepool { /* code */ }
What does that mean? Does it mean that if my code base doesn't have any Objective-C files, autoreleasepool {} is unnecessary?
In an answer of a related question, there is an example where autoreleasepool can be useful:
- (void)useALoadOfNumbers {
for (int j = 0; j < 10000; ++j) {
#autoreleasepool {
for (int i = 0; i < 10000; ++i) {
NSNumber *number = [NSNumber numberWithInt:(i+j)];
NSLog(#"number = %p", number);
}
}
}
}
If the code above gets translated into Swift with autoreleasepool dropped, will Swift be smart enough to know that the number variable should be released after the first } (like some other languages does)?
The autoreleasepool pattern is used in Swift when returning autorelease objects (created by either your Objective-C code or using Cocoa classes). The autorelease pattern in Swift functions much like it does in Objective-C. For example, consider this Swift rendition of your method (instantiating NSImage/UIImage objects):
func useManyImages() {
let filename = pathForResourceInBundle
for _ in 0 ..< 5 {
autoreleasepool {
for _ in 0 ..< 1000 {
let image = NSImage(contentsOfFile: filename)
}
}
}
}
If you run this in Instruments, you'll see an allocations graph with 5 small hills (because outer for-loop), like the following:
But if you do it without the autorelease pool, you'll see that peak memory usage is higher:
The autoreleasepool allows you to explicitly manage when autorelease objects are deallocated in Swift, just like you were able to in Objective-C.
Note: When dealing with Swift native objects, you generally will not receive autorelease objects. This is why the presentation mentioned the caveat about only needing this when "working with Objective-C", though I wish Apple was more clear on this point. But if you're dealing with Objective-C objects (including Cocoa classes), they may be autorelease objects, in which case this Swift rendition of the Objective-C #autoreleasepool pattern is still useful.
If you would use it in the equivalent Objective-C code, then you would use it in Swift.
will Swift be smart enough to know that the number variable should be
released after the first }
Only if Objective-C does. Both operate along the Cocoa memory management rules.
Of course ARC knows that number goes out of scope at the end of that iteration of the loop, and if it retained it, it will release it there. However, that does not tell you whether the object was autoreleased, because -[NSNumber numberWithInt:] may or may not have returned an autoreleased instance. There is no way you can know, because you don't have access to the source of -[NSNumber numberWithInt:].
#autoreleasepool can be used in Objective-C and Swift code to guarantee working with Objective-C code which relies on autorelease
[Under the hood]
I am using a variable inside a function with holds and UnsafeMutablePointer<objc_property_t>. Should I call free on it?
func logProps() {
var count: UInt32 = 0
let _propArr = class_copyPropertyList(cls, &count)
// ...
// free(propArr) // ?
}
On a different note, is free same as using deallocate (Swift UnsafeMutablePointer: Must I call deinitialize before deallocate?) ?
Yes, because of the name of the method. class_copyPropertyList includes the word "copy" which indicates that the buffer belongs to you. Note that the documentation also indicates this:
You must free the array with free().
So you should use free() to destroy this buffer. This is currently identical to calling .deallocate(), but that is not promised, so follow the instructions as given.
(Thanks to MartinR for running down the question of free vs deallocate.)
On page 17 of this WWDC14 presentation, it says
Working with Objective-C? Still have to manage autorelease pools
autoreleasepool { /* code */ }
What does that mean? Does it mean that if my code base doesn't have any Objective-C files, autoreleasepool {} is unnecessary?
In an answer of a related question, there is an example where autoreleasepool can be useful:
- (void)useALoadOfNumbers {
for (int j = 0; j < 10000; ++j) {
#autoreleasepool {
for (int i = 0; i < 10000; ++i) {
NSNumber *number = [NSNumber numberWithInt:(i+j)];
NSLog(#"number = %p", number);
}
}
}
}
If the code above gets translated into Swift with autoreleasepool dropped, will Swift be smart enough to know that the number variable should be released after the first } (like some other languages does)?
The autoreleasepool pattern is used in Swift when returning autorelease objects (created by either your Objective-C code or using Cocoa classes). The autorelease pattern in Swift functions much like it does in Objective-C. For example, consider this Swift rendition of your method (instantiating NSImage/UIImage objects):
func useManyImages() {
let filename = pathForResourceInBundle
for _ in 0 ..< 5 {
autoreleasepool {
for _ in 0 ..< 1000 {
let image = NSImage(contentsOfFile: filename)
}
}
}
}
If you run this in Instruments, you'll see an allocations graph with 5 small hills (because outer for-loop), like the following:
But if you do it without the autorelease pool, you'll see that peak memory usage is higher:
The autoreleasepool allows you to explicitly manage when autorelease objects are deallocated in Swift, just like you were able to in Objective-C.
Note: When dealing with Swift native objects, you generally will not receive autorelease objects. This is why the presentation mentioned the caveat about only needing this when "working with Objective-C", though I wish Apple was more clear on this point. But if you're dealing with Objective-C objects (including Cocoa classes), they may be autorelease objects, in which case this Swift rendition of the Objective-C #autoreleasepool pattern is still useful.
If you would use it in the equivalent Objective-C code, then you would use it in Swift.
will Swift be smart enough to know that the number variable should be
released after the first }
Only if Objective-C does. Both operate along the Cocoa memory management rules.
Of course ARC knows that number goes out of scope at the end of that iteration of the loop, and if it retained it, it will release it there. However, that does not tell you whether the object was autoreleased, because -[NSNumber numberWithInt:] may or may not have returned an autoreleased instance. There is no way you can know, because you don't have access to the source of -[NSNumber numberWithInt:].
#autoreleasepool can be used in Objective-C and Swift code to guarantee working with Objective-C code which relies on autorelease
[Under the hood]
I'm working, tentatively, with the AudioToolbox API using Swift 2.0 and Xcode 7b6. The API uses a lot of c-language constructs, including function pointers. This is my first time working with commands like withUnsafeMutablePointer and unsafeBitCast. I am looking for a reality check to make sure that I am not way off base in what I am doing.
For example, to open a file stream, you use the following function:
func AudioFileStreamOpen(
_ inClientData: UnsafeMutablePointer<Void>
, _ inPropertyListenerProc: AudioFileStream_PropertyListenerProc
, _ inPacketsProc: AudioFileStream_PacketsProc
, _ inFileTypeHint: AudioFileTypeID
, _ outAudioFileStream: UnsafeMutablePointer<AudioFileStreamID>) -> OSStatus
Just the type signature of the function makes me start to sweat.
At any rate, the inClientData parameter needs to be an UnsafeMutablePointer<Void>, and the pointer will point to an instance of the same class I am working in. In other words, it needs to be a pointer to self. My approach is to call the function using withUnsafeMutablePointer like this:
var proxy = self
let status = withUnsafeMutablePointer(&proxy) {
AudioFileStreamOpen($0, AudioFileStreamPropertyListener
, AudioFileStreamPacketsListener, 0, &audioFileStreamID)
}
My first question is whether or not I'm using withUnsafeMutablePointer correctly here. I wasn't sure how to get a pointer to self - just writing &self doesn't work, because self is immutable. So I declared proxy as a variable and passed a reference to that, instead. I don't know if this will work or not, but it was the best idea I came up with.
Next, AudioFileStreamPropertyListener and AudioFileStreamPacketsListener are C callback functions. They each get passed the pointer to self that I created using withUnsafeMutablePointer in AudioFileStreamOpen. The pointer is passed in as an UnsafeMutablePointer<Void>, and I need to cast it back to the type of my class (AudioFileStream). To do that, I believe I need to use unsafeBitCast. For example, here is AudioFileStreamPropertyListener:
let AudioFileStreamPropertyListener: AudioFileStream_PropertyListenerProc
= { inClientData, inAudioFileStreamID, inPropertyID, ioFlags in
let audioFileStream = unsafeBitCast(inClientData, AudioFileStream.self)
audioFileStream.didChangeProperty(inPropertyID, flags: ioFlags)
}
That compiles fine, but again I'm not sure if I'm using unsafeBitCast correctly, or if that is even the correct function to be using in this kind of situation. So, is unsafeBitCast the correct way to take an UnsafeMutablePointer<Void> and cast it to a type that you can actually use inside of a C function pointer?
It's interesting that the inClientData "context" param is bridged as UnsafeMutablePointer, since I doubt the AudioToolbox APIs will modify your data. It seems it would be more appropriate if they'd used COpaquePointer. Might want to file a bug.
I think your use of withUnsafeMutablePointer is wrong. The pointer ($0) will be the address of the variable proxy, not the address of your instance. (You could say $0.memory = [a new instance] to change it out for a different instance, for example. This is a bit confusing because its type is UnsafeMutablePointer<MyClass> — and in Swift, the class type is itself a pointer/reference type.)
I was going to recommend you use Unmanaged / COpaquePointer, but I tested it, and realized this does exactly the same thing as unsafeAddressOf(self)!
These are equivalent:
let data = UnsafeMutablePointer<Void>(Unmanaged.passUnretained(self).toOpaque())
let data = unsafeAddressOf(self)
And these are equivalent:
let obj = Unmanaged<MyClass>.fromOpaque(COpaquePointer(data)).takeUnretainedValue()
let obj = unsafeBitCast(data, MyClass.self)
While the Unmanaged approach makes logical sense, I think you can see why it might be prefereable to use unsafeAddressOf/unsafeBitCast :-)
Or, you might consider an extension on Unmanaged for your own convenience:
extension Unmanaged
{
func toVoidPointer() -> UnsafeMutablePointer<Void> {
return UnsafeMutablePointer<Void>(toOpaque())
}
static func fromVoidPointer(value: UnsafeMutablePointer<Void>) -> Unmanaged<Instance> {
return fromOpaque(COpaquePointer(value))
}
}
Then you can use:
let data = Unmanaged.passUnretained(self).toVoidPointer()
let obj = Unmanaged<MyClass>.fromVoidPointer(data).takeUnretainedValue()
Of course, you will need to ensure that your object is being retained for the duration that you expect it to be valid in callbacks. You could use passRetained, but I would recommend having your top-level controller hold onto it.
See some related discussion at https://forums.developer.apple.com/thread/5134#15725.