我正在进行一项性能测试,试图测量我的Mac应用程序中一个重要的
我注意到内存使用量正在增加。在我的
但是,我发现我的NSOutlineViews、它们的行和行模型仍然存在。有数千个,所以它真的让内存使用量飙升。
我使用Instruments的Leak工具进行了性能分析:没有泄漏。
然后我在内存图调试器中检查了这些对象。没有明显的强引用循环,所有对象的情况都类似于这个例子。它是一个NSOutlineView(实际上是一个动态的
NSOutlineView
的渲染性能。在此过程中,我循环多次,创建视图,将其嵌入虚拟窗口中,并将其渲染为图像。总体而言,大致如下:// Intentionally de-indented these for easier reading in this narrow page
class MyPerformanceTest: XCTestCase { reading
func test() {
measure() {
// autoreleasepool {
let window: NSWindow = {
let w = NSWindow(
contentRect: NSRect.init(x: 100, y: 100, width: 800, height: 1200),
styleMask: [.titled, .resizable, .closable, .miniaturizable],
backing: .buffered,
defer: false
)
w.tabbingMode = .disallowed
w.cascadeTopLeft(from: NSPoint(x: 200, y: 200))
w.makeKeyAndOrderFront(nil)
w.contentView = testContentView // The thing I'm performance testing
return w
}()
let bitmap = self.bitmapImageRepForCachingDisplay(in: self.frame)
.map { bitmap in
self.cacheDisplay(in: self.frame, to: bitmap)
return bitmap
}
let data = bitmap.representation(using: .png, properties: [:])!
saveToDesktop(data, name: "image1.png") // Helper function around Data.write(to:). Boring.
window.isReleasedWhenClosed = false // Defaults to true, but crashes if true.
window.close()
// }
}
}
}
我注意到内存使用量正在增加。在我的
measure(_:)
块的每个循环中分配的每个窗口都一直存在,这是有道理的,因为我没有运行主run loop,所以线程的自动释放池从未被清除。我在整个measure
块中包装了一个autoreleasepool
block的调用,问题得到解决。使用内存图调试器,我确认最多只有1个窗口,即当前迭代的窗口。太好了。但是,我发现我的NSOutlineViews、它们的行和行模型仍然存在。有数千个,所以它真的让内存使用量飙升。
我使用Instruments的Leak工具进行了性能分析:没有泄漏。
然后我在内存图调试器中检查了这些对象。没有明显的强引用循环,所有对象的情况都类似于这个例子。它是一个NSOutlineView(实际上是一个动态的
NSKVONotifying_*
子类,但这并不重要),只有一个来自ObjC块的强引用。但是那个块只被一个引用(黑色线条)弱引用。整个东西难道不应该被释放吗?
我该如何排除为什么这个东西一直保持着活动状态的问题?
setup
里面设置了什么吗?每次重新发现那些东西一直保留到所有测试结束,我都感到惊讶。 - mattwindow.isReleasedWhenClosed = false
怎么样?这样会不会导致窗口堆积? - matttrue
会导致window.close()
崩溃 :| (我弄不清楚为什么)而且这不是窗口堆积(它们在最后的自动释放池中被清除),而是NSOutlineviews(但不包括滚动或剪辑视图)。我应该使用什么工具来跟踪保留/释放?我知道有关分配和泄漏的工具,但我不知道是否有专门跟踪特定对象的保留/释放的工具。这是真的吗? - Alexander