SceneKit - Неограниченная причина роста памяти при поиске childNode - PullRequest
1 голос
/ 12 марта 2019

У меня есть приложение, которое выполняет манипуляции с SCNNode s в цикле - память приложения уходит до 2 ГБ и вылетает.Мой настоящий цикл очень сложен - он включает в себя обновление simdWorldTransform узлов, а также удаление и добавление узлов.

Чтобы упростить его до такой степени, что я могу задать этот вопрос, я сделал простой пример, когда при нажатии кнопки он выполняет очень простые действия, такие как извлечение дочернего узла SCNNode - он все еще достигает 2 ГБ исбои.

Функция:

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]

        }
    }

Кажется, что виновником является вызов extractSprite - потому что, если я уберу этохраня ссылки на спрайт в массиве, программа больше не падает.Я включаю метод extractSprite.Я совершенно ошеломлен, почему это вызывает неограниченный рост памяти.Что вызывает этот взрыв памяти?Я просто ищу узел?После выхода из итерации не должно быть никаких закулисных ссылок?

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 Ответ

1 голос
/ 12 марта 2019

Для всех, кто имеет дело с этой ситуацией и, кажется, их много, следующие шаги решили проблему.

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

Как и предполагал @ElTomato, поскольку цикл потенциально может создавать временные объекты в цикле, рекомендуется использовать autoreleasepool. В документации Apple: «Вы можете использовать блок пула автоматического выпуска внутри цикла, чтобы избавиться от этих объектов перед следующей итерацией. Использование блока пула автоматического выпуска в цикле помогает уменьшить максимальный объем памяти приложения».

Пример:

// add leaderLineNodes
        for leaderLine in createleaderLineNodes(labelComponent: labelComponent) {
            autoreleasepool {
                labelComponent.addChildNode(leaderLine)
            }
        }
  1. Запустите разрабатываемое приложение в «режиме выпуска».

Производительность в XCode может отличаться от реальной производительности устройства. Пункты 2 и 3 оказали сильное влияние на мое приложение как на объем памяти, так и на скорость выполнения. Сначала я был очень удивлен, когда профилировал приложение в Instruments, обнаружив, что используемая память была намного меньше, чем раньше - оказывается, Instruments запускает приложение в режиме Release.

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

  1. Отключить ведение журнала

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

...