我正在嘗試修復記憶體泄漏(以下代碼)。
public func withNSString(
_ chars: UnsafePointer<Int8>,
_ callback: (NSString) -> Void
) {
let result: NSString = NSString(utf8String: chars)!;
callback(result);
}
作為個人政策,使用單元測驗,例如:
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?
}
}
為什么上次XCTAssertNil呼叫失敗?
(換句話說,我該如何修復記憶體泄漏?)
uj5u.com熱心網友回復:
問題是您使用的是非常短的靜態字串。它被行內到堆疊中,因此在整個堆疊框架超出范圍之前它不會被釋放。如果您使字串長一點(長 2 個字符),這將按照您期望的方式運行。當然,這是一個實作細節,可能會因編譯器版本不同、作業系統版本不同、優化設定不同或架構不同而發生變化。
請記住,使用任何型別的靜態字串測驗此類事情可能會很棘手,因為靜態字串已放入二進制檔案中。因此,如果編譯器注意到您間接地創建了一個指向靜態字串的指標,那么它可能會優化間接性而不是釋放它。
但是,在這些情況下都沒有記憶體泄漏。您的記憶體泄漏更有可能出現在 的呼叫代碼中withNSString。我主要懷疑您沒有正確處理作為chars. 我們需要更多地了解您認為存在泄漏的原因來評估這一點。(Foundation 也有一些小的泄漏,而 Instruments 對泄漏有誤報,因此如果您正在尋找小于 50 位元組的分配,并且不會在每個操作中都重復出現,那么您可能正在尋找幽靈。)
請注意,這有點危險:
let chars = ("some data" as NSString).utf8String!
withNSString(chars, { strongRef in
該utf8String內部指標不答應活的比NSString的長,斯威夫特是免費摧毀他們的最后一個參考后物件(這可能是他們走出去的范圍之前)。正如檔案所述:
這個C字串是一個指向字串物件內部結構的指標,它的生命周期可能比字串物件短,肯定不會有更長的生命周期。因此,如果需要將 C 字串存盤在使用此屬性的記憶體背景關系之外,則應復制 C 字串。
在這種情況下,物件是一個常量字串,它在二進制中并且不能被銷毀。但在更一般的情況下,這是導致崩潰的典型原因。我強烈建議遠離 NSString 介面并使用 String。它提供utf8CString,它回傳一個正確的 ContinguousArray,它更安全。
let chars = "some data".utf8CString
chars.withUnsafeBufferPointer { buffer in
withNSString(buffer.baseAddress!, { strongRef in
weakRef = strongRef;
XCTAssertNotNil(weakRef);
})
}
withUnsafeBufferPointer確保chars在塊完成之前不能被銷毀。
如果需要,您還可以確保字串的生命周期(這對于修復您不想以更安全的方式重寫的舊代碼非常有用):
let string = "some data"
withExtendedLifetime(string) {
let chars = string.utf8CString
chars.withUnsafeBufferPointer { buffer in
withNSString(buffer.baseAddress!, { strongRef in
weakRef = strongRef;
XCTAssertNotNil(weakRef);
})
}
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/331476.html
