【问题标题】:Updating environment object causes memory to keep growing with each update更新环境对象会导致内存随着每次更新而不断增长
【发布时间】:2020-11-22 02:11:46
【问题描述】:

我创建了一个新应用程序,代表我在实际应用程序中遇到的类似情况。基本上,我正在更新用于呈现 UI 的可观察对象的值。并且由于某种原因导致内存随着每次迭代而不断增长。我还注意到,内存增长量取决于每秒迭代次数和 ContentView 中视图的数量/类型。

注意:被更新的可观察对象是self.infoObj.text = "Counter: \(counter)"

AppDelgate.swift

func applicationDidFinishLaunching(_ aNotification: Notification) {
    infoObj = InfoObj()

    // Create the SwiftUI view that provides the window contents.
    let contentView = ContentView()
        .environmentObject(infoObj)

    // Create the window and set the content view. 
    window = NSWindow(
        contentRect: NSRect(x: 0, y: 0, width: 480, height: 300),
        styleMask: [.titled, .closable, .miniaturizable, .resizable, .fullSizeContentView],
        backing: .buffered, defer: false)
    window.center()
    window.setFrameAutosaveName("Main Window")
    window.contentView = NSHostingView(rootView: contentView)
    window.makeKeyAndOrderFront(nil)
    
    var counter = 0;
    
    DispatchQueue.global(qos: .userInteractive).async {
        while(true) {
            usleep(1000)
            counter += 1
            DispatchQueue.main.sync {
                self.infoObj.text = "Counter: \(counter)"
            }
        }
    }
}

ContentView.swift

struct ContentView: View {
    @EnvironmentObject var infoObj: InfoObj
    
    var body: some View {
        VStack {
            HStack {
                Text("Text 11")
                    .frame(maxWidth: .infinity, maxHeight: .infinity)
                Text("Text 12")
                    .frame(maxWidth: .infinity, maxHeight: .infinity)
                Text("Text 13")
                    .frame(maxWidth: .infinity, maxHeight: .infinity)
                Text("Text 14")
                    .frame(maxWidth: .infinity, maxHeight: .infinity)
                Text("Text 15")
                    .frame(maxWidth: .infinity, maxHeight: .infinity)
            }
            Text(infoObj.text)
                .frame(maxWidth: .infinity, maxHeight: .infinity)
            HStack {
                Text("Text 21")
                    .frame(maxWidth: .infinity, maxHeight: .infinity)
                Text("Text 22")
                    .frame(maxWidth: .infinity, maxHeight: .infinity)
                Text("Text 23")
                    .frame(maxWidth: .infinity, maxHeight: .infinity)
                Text("Text 24")
                    .frame(maxWidth: .infinity, maxHeight: .infinity)
                Text("Text 25")
                    .frame(maxWidth: .infinity, maxHeight: .infinity)
            }
            HStack {
                Text("Text 31")
                    .frame(maxWidth: .infinity, maxHeight: .infinity)
                Text("Text 32")
                    .frame(maxWidth: .infinity, maxHeight: .infinity)
                Text("Text 33")
                    .frame(maxWidth: .infinity, maxHeight: .infinity)
                Text("Text 34")
                    .frame(maxWidth: .infinity, maxHeight: .infinity)
                Text("Text 35")
                    .frame(maxWidth: .infinity, maxHeight: .infinity)
            }
            HStack {
                Text("Text 41")
                    .frame(maxWidth: .infinity, maxHeight: .infinity)
                Text("Text 42")
                    .frame(maxWidth: .infinity, maxHeight: .infinity)
                Text("Text 43")
                    .frame(maxWidth: .infinity, maxHeight: .infinity)
                Text("Text 44")
                    .frame(maxWidth: .infinity, maxHeight: .infinity)
                Text("Text 45")
                    .frame(maxWidth: .infinity, maxHeight: .infinity)
            }
            HStack {
                Text("Text 51")
                    .frame(maxWidth: .infinity, maxHeight: .infinity)
                Text("Text 52")
                    .frame(maxWidth: .infinity, maxHeight: .infinity)
                Text("Text 53")
                    .frame(maxWidth: .infinity, maxHeight: .infinity)
                Text("Text 54")
                    .frame(maxWidth: .infinity, maxHeight: .infinity)
                Text("Text 55")
                    .frame(maxWidth: .infinity, maxHeight: .infinity)
            }
        }
    }
}


struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

class InfoObj: ObservableObject {
    @Published var text = "initial"
}

您能帮我理解发生这种情况的原因吗?我该如何解决?另外,为什么代码工具没有将其视为内存泄漏?

【问题讨论】:

    标签: swift macos memory-leaks


    【解决方案1】:

    您只是在堆栈上同步循环执行,因此您观察到堆栈增长(不作为泄漏内存处理)。

    解决方案是改为异步计数器处理并将所有内容移入 EnvironmentObject

    class InfoObj: ObservableObject {
        private var counter = 0
        @Published var text = "initial" {
            didSet {
                print(">> " + text)   // << used for testing
            }
        }
    
        func runCounter() {
            counter += 1
            text = "Counter: \(self.counter)"
    
            // !! There is no sense to update UI with 1 milisecond 
            // (but you can tune interval below as you need)
            DispatchQueue.main.asyncAfter(deadline: .now() + 0.05, execute: runCounter)
        }
    }
    

    并使用

        // ... other code
        window.contentView = NSHostingView(rootView: contentView)
        window.makeKeyAndOrderFront(nil)
    
        infoObj.runCounter()      // << here !!    
    }
    

    【讨论】:

    • DispatchQueue.global(qos: .userInteractive).async 块还不足以异步执行吗?问题是我的实际应用不仅仅是一个简单的计数器,而是一个通过 TCP 带来的值,预计每秒更新多次。
    • 另外,即使我将DispatchQueue.main.sync { self.infoObj.text = "Counter: \(counter)" } 更改为DispatchQueue.main.async { self.infoObj.text = "Counter: \(counter)" } 我仍然遇到同样的问题。
    • 好的,实际上没有,使用DispatchQueue.main.async { self.infoObj.text = "Counter: \(counter)" } 似乎可以解决这个问题。另一个问题,如果我使用sync 选项,有没有办法强制释放内存?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多