试图修复300MB内存泄漏,并在发现泄漏原因后;
(它是从C++线程调用
NSString的stringFromUTF8String:(没有@autoreleasepool-block包装))
我编辑了代码,以执行引用计数(而不是自动发布),如下所示:
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 调用失败?
(换句话说,我如何修复内存泄漏?)
发布于 2021-10-22 13:37:47
问题是你用的是一个很短的字符串。它被内联到堆栈上,所以直到整个堆栈帧超出范围后才会释放。如果您使字符串稍微长一点(2个字符长),这将按照您预期的方式进行。当然,这是一个实现细节,并且可能由于编译器的不同版本、操作系统的不同版本、不同的优化设置或不同的体系结构而发生变化。
请记住,使用任何类型的静态字符串来测试这类事情是很棘手的,因为静态字符串被放置到二进制文件中。因此,如果编译器注意到您间接地创建了一个指向静态字符串的指针,那么它可能会优化间接方向,而不是释放它。
但是,在所有这些情况下,都不存在内存泄漏。您的内存泄漏更有可能出现在withNSString的调用代码中。我主要怀疑您没有正确地处理作为chars传递的字节。我们需要更多地了解为什么你认为有一个漏洞来评估它。(Foundation也有一些小泄漏,而仪器在泄漏方面有假阳性,所以如果您在追逐小于50个字节的分配,并且没有在每个操作中重复,那么您可能是在追逐鬼魂。)
请注意,这有点危险:
let chars = ("some data" as NSString).utf8String!
withNSString(chars, { strongRef inutf8String内部指针不会比NSString更长,而且Swift可以在对象上次引用之后(可能是在它们超出作用域之前)自由地销毁它们。正如医生们所指出的:
此C字符串是指向string对象内部结构的指针,该结构的生存期可能比string对象短,并且肯定不会有更长的生存期。因此,如果C字符串需要存储在使用此属性的内存上下文之外,则应复制它。
在这种情况下,对象是一个常量字符串,它在二进制文件中,不能被销毁。但在更普遍的情况下,这是典型的撞车原因。我强烈建议远离NSString接口,使用字符串。它提供了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://stackoverflow.com/questions/69677467
复制相似问题