Saya memiliki aplikasi yang melakukan manipulasi ke SCNNode dalam satu lingkaran - memori aplikasi menjadi 2GB dan macet. Loop saya yang sebenarnya sangat terlibat - termasuk memperbarui simdWorldTransform node, serta menghapus dan menambahkan node.

Untuk menyederhanakannya ke titik di mana saya dapat mengajukan pertanyaan ini, saya melakukan contoh sederhana di mana dengan menekan tombol, ia menjalankan tindakan yang sangat sederhana seperti mengambil anak dari SCNNode - masih mencapai 2GB dan macet.

Fungsi:

func memoryLeakDetect() {

        for i in 1..<2001 {
            if i % 10 == 0 {
                print("Iteration = \(i)")
            }
            simpleLoop()
        }
    }

simpleLoop():

func simpleLoop() {
        for i in 0..<10000 {

            let pickIndex     = 1
            let pickLabelComp = saLabelComponents[pickIndex]
            let pickSprite    = LabelCompUtils.extractSprite(from: pickLabelComp) //MARK: CAUSING MEMORY LEAK!!!!
            // let pickSprite = saSprites[pickIndex]

        }
    }

Tampaknya pelakunya adalah panggilan ke extractSprite - karena jika saya menghapusnya dengan menyimpan referensi ke sprite dalam array, program tidak lagi macet. Saya menyertakan metode extractSprite. Saya benar-benar tercengang mengapa ini menyebabkan pertumbuhan memori yang tidak terbatas. Apa yang menyebabkan ledakan memori ini? Saya hanya mencari simpul? Seharusnya tidak ada referensi yang disimpan di belakang layar setelah saya keluar dari iterasi?

class LabelCompUtils {

    static func extractSprite(from labelComponent: SCNNode) -> SCNNode {
        if let sprite: SCNNode = labelComponent.childNode(withName: "sprite", recursively: false) {
            return sprite
        } else {
            return SCNNode()
        }
    }
1
oneiros 12 Maret 2019, 04:32

1 menjawab

Jawaban Terbaik

Untuk siapa pun yang berurusan dengan situasi ini dan tampaknya ada banyak, langkah-langkah berikut menyelesaikan masalah.

  1. autoreleasepool: https:// developer.apple.com/library/archive/documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmAutoreleasePools.html

Seperti yang disarankan @ElTomato, karena loop berpotensi membuat objek sementara dalam satu loop, penggunaan autoreleasepool direkomendasikan. Per dokumentasi Apple: "Anda dapat menggunakan blok kumpulan rilis otomatis di dalam loop untuk membuang objek tersebut sebelum iterasi berikutnya. Menggunakan blok kumpulan rilis otomatis dalam loop membantu mengurangi jejak memori maksimum aplikasi."

Contoh:

// add leaderLineNodes
        for leaderLine in createleaderLineNodes(labelComponent: labelComponent) {
            autoreleasepool {
                labelComponent.addChildNode(leaderLine)
            }
        }
  1. Jalankan aplikasi yang Anda kembangkan dalam "mode rilis".

Kinerja di Xcode mungkin tidak sama dengan kinerja perangkat dunia nyata. Poin 2 dan 3 sangat memengaruhi aplikasi saya dengan jejak memori dan kecepatan eksekusi. Awalnya saya sangat terkejut ketika membuat profil aplikasi di Instrumen untuk mengetahui bahwa memori yang digunakan jauh lebih rendah dari sebelumnya - ternyata Instrumen menjalankan aplikasi dalam mode Rilis.

Product -> Scheme -> Edit Scheme -> Info -> Build Configuration -> Release Mode

  1. Nonaktifkan Pencatatan

Product -> Scheme -> Edit Scheme -> Diagnostics -> Logging

1
oneiros 12 Maret 2019, 15:41