Weird Memory Behavior in Swift - swift

OK... so I have no idea why this happens but:
Compare the following two lines:
let pointCurve: [AnyObject] = self.curve.map{NSValue(point:$0)}
and
let pointCurve: [NSPoint] = self.curve.map{$0}
In either case, the variable is local and not used at all after assignment. The line resides in a method that is called repeatedly and very quickly. The first case results in terrible and ever faster growing of memory usage. But when I change it to the second, the memory stats are flat as a disc.
You may say, "oh, you're not doing anything in the second line". So I tried the following:
var pointCurve: [AnyObject] = []
for c in self.curve {
pointCurve.append(NSValue(point:NSPoint(x:1, y:1))
}
vs
var pointCurve: [NSPoint] = []
for c in self.curve {
pointCurve.append(NSPoint(x: 1, y: 1))
}
Now I see the exact same results. The culprit seems to be NSValue. I checked with Instruments that a whole bunch of NSConcreteValues are allocated, and I read online these are related to NSValue. But I didn't find anything about them causing memory leaks.
The question is what can I do about this. I'm supposed to send an array of points to some ObjC code, and until I figure out how to fix this, I can't do it without huge performance issues.

Try:
func pointCurvy() {
autoreleasepool {
let pointCurve: [AnyObject] = self.curve.map{NSValue(point:$0)}
// Do something with pointCurve.
}
}

Related

How to test NSString with autoreleasepool leak?

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);
})
}
}

Array element assignment causes expensive _ArrayBufferProtocol.init(copying:)

I have the following class, grossly simplified
class MyClass {
var largeArray: [Int] = []
init() {
largeArray.reserveCapacity(10000000)
... lots of code to add 10000000 various elements to largeArray
}
func mutateArray(idx: Int) {
largeArray[idx] = someVal
}
}
Surprisingly, when profiling this code, calls to mutateArray turned out to be very expensive, with most of the time spent
in _ArrayBufferProtocol.init(copying:), and some in _swift_release_dealloc. The time spent is proportional to the number of calls to mutateArray, indicating
that this happens every time the method is called.
Why is this happening? Is there any way to avoid it?
Your array's buffer leaks out of its MyClass encapsulation somewhere.
If largeArray is initialized within a MyClass object, it has sufficient capacity reserved up front, and you've never let anyone else have access to your class, or alias it yourself, then you couldn't possibly cause a CoW copy.
You should set var largeArray to private. Not only will that enforce the capsulation you're in need of, but it'll also show you what else is accessing this.

Swift: Repeatedly calling a closure passed through identity function causes EXC_BAD_ACCESS code=2

Update:
Here's an even simpler reproduction that doesn't use arrays (h/t to Tim):
func identity<T>(_ v: T) -> T {
return v
}
var closure = {
return
}
while true {
closure()
closure = identity(closure)
}
Running this code causes a stack overflow. I'm filing a bug with Swift.
Original:
Original title: Swift: Array of closures causes EXC_BAD_ACCESS code=2
I'm trying to understand why this code produces a EXC_BAD_ACCESS code=2. Here's the code:
var closures: [() -> ()] = []
closures.append({
return
})
while true {
var newClosures: [() -> ()] = []
for closure in closures {
closure()
newClosures.append(closure)
}
closures = newClosures
}
I've tried to distill the problem down to as few lines as possible, which is why the code might seem a little strange and pointless. (Its only "point" is to demonstrate the issue I'm having with as few lines as possible.)
If you run this code in XCode as a macOS console app, you'll see that memory is being allocated without being freeed. In Instruments I can see memory is allocated at newClosures.append(closure), which makes sense. What I don't understand is why assigning closures to newClosures doesn't free the old version of newClosures. Instead the allocations seem to grow infinitely until I EXC_BAD_ACCESS code=2.
It's also worth noting that it doesn't even allocate much memory. In my testing the application crashes after allocating around 17MB (it starts at around 5MB, and ramps up to 17MB in about 60s). So I think it's something to do with the number of objects being retained, rather than the pure size of them.
If I replace the closures array with an array to some other reference type, e.g.
class Foo { }
var foos: [Foo] = []
foos.append(Foo())
while true {
var newFoos: [Foo] = []
for foo in foos {
newFoos.append(foo)
}
foos = newFoos
}
It works as expected. I think something must be going on where the closure is capturing more and more stuff every time through the loop? But I don't understand how that could be.
I could probably refactor the code to work around the issue, but at this point I just want to understand what's going on.
This is a bug in Swift. Track the issue here, https://bugs.swift.org/browse/SR-7179.

memory usage increases dramatically after each FMDB query

Below is my source code, every time I execute the function, the memory usage increases dramatically. Please help to point out what is the problem.
func loadfontsFromDatabase(code:String)->[String] {
let documentsPath : AnyObject = NSSearchPathForDirectoriesInDomains(.documentDirectory,.userDomainMask,true)[0] as AnyObject
let databasePath = documentsPath.appending("/bsmcoding.sqlite")
let contactDB = FMDatabase(path: databasePath as String)
var c:[String]=[]
let querySQL = "SELECT FONT FROM BSMCODE WHERE BSMCODE.CODE = '\(code)' ORDER BY NO DESC"
NSLog("query:\(querySQL)")
let results:FMResultSet? = Constants.contactDB?.executeQuery(querySQL, withArgumentsIn: nil)
while (results?.next())! {
c.append((results?.string(forColumn: "FONT"))!)
}
results?.close()
return c
}
There's nothing here that would account for any substantial memory loss. I would suggest using the "Debug Memory Graph" feature in Xcode 8 to identify what objects are being created and not being released, but I suspect the problem rests elsewhere in your code. Or use Instruments to track it down what's leaking and debug from there. See https://stackoverflow.com/a/30993476/1271826.
There are unrelated issues here, though:
You are creating local contactDB, but you never open it and you never use it. It will be released when the routine exits, but it's completely unnecessary if you're going to use Constants.contactDB, anyway.
I'd advise against using string interpolation when building your SQL. Use ? placeholder and pass the code in as a parameter. This is much safer, in case the code ever contained something that couldn't be represented in SQL statement. (This is especially true if the code was supplied by the user, in which case you'd be susceptible to SQL injection attacks or innocent input errors that could lead to crashes.)
For example, you could do something like:
func loadfontsFromDatabase(code: String) -> [String] {
var c = [String]()
let querySQL = "SELECT FONT FROM BSMCODE WHERE BSMCODE.CODE = ? ORDER BY NO DESC"
let results = try! Constants.contactDB!.executeQuery(querySQL, values: [code])
while results.next() {
c.append((results.string(forColumn: "FONT"))!)
}
return c
}
If you don't like the forced unwrapping, you can do optional unwrapping if you want, but personally I'd rather know immediately when debugging during the development phase if there's some logic mistake (e.g. the contactDB wasn't open, the SQL is incorrect, etc.). But you can do optional binding and add the necessary guard statements if you want. But don't just do optional binding and silently return a value suggesting that everything is copacetic, leaving you with a debugging challenge of tracking down the problem if you don't get what you expected.
But the key point is to avoid inserting values into your SQL directly. Use ? placeholders.

Pitfall in Swift Type Casting

I am not totally sure if this the right place to post this, as it is more a pitfall I have found than a question I would ask. (Although I would be very interested if someone could explain the reason why this happens.)
So in my Swift iOS-app I had to use Objective-C Arrays for sorting. I knew for a fact that the NSMutableArray called results would contain only MyObjects. Thus, after sorting I cast it to [MyObject] like this to save it in the variable myArrayVar : [MyObject].
myArrayVar = (results as NSArray) as [MyObject]
This worked fine until I tested it on a release build. There it crashed. What I had to do to fix the crash was this:
if let results = results as Any as? NSArray {
if let results = results as? [MyObject] {
myArrayVar = results
} else { NSLog("the impossible happened.") }
} else { NSLog("the impossible happened.") }
Now we can see that this version cannot crash when the casting goes wrong whereas the first version would. However, the cast does not go wrong as I could verify by never seeing the log message.
So what might be the difference at runtime between these two versions of type casting? Whatever it is I have the feeling it might be a pitfall for others as well.