SpriteKit Does Not Free All Used Memory

I have many (if not all) articles about SO and other disaster sites related to SpriteKit and memory issues. My problem, like many others, is that after I left the scene with SpriteKit, you free some of the memory added during the scene session. I tried to implement all the proposed solutions in the articles you found, including, but not limited to ...

1) Confirm that the method deinitis being called in the SKScene class.

2) Confirm the strongreferences to the parent VC in the scene class.

3) Strongly remove all children and activities and set the scene to nilwhen the VC disappears. (Setting the scene to nilwas what the method received deinitin order to get the call as a result)

However, after all this, memory still exists. In a way, this application goes between the standard UIKit view controllers and the SpriteKit scene (this is a professional drawing application). As an example, the application uses about 400 MB before entering the SpriteKit scene. After entering the scene and creating several nodes, the amount of memory increases to 1 GB (everything is still good). When I leave the scene, memory drops about 100 MB. And if I enter the scene again, he continues to pile up. Are there any ways or suggestions on how to completely free up all the memory that was used during a SpriteKit session? The following are some of the methods that are used to resolve this problem.

SKScene Class

func cleanScene() {
    if let s = self.view?.scene {
        NotificationCenter.default.removeObserver(self)
        self.children
            .forEach {
                $0.removeAllActions()
                $0.removeAllChildren()
                $0.removeFromParent()
        }
        s.removeAllActions()
        s.removeAllChildren()
        s.removeFromParent()
    }
}

override func willMove(from view: SKView) {
    cleanScene()
    self.removeAllActions()
    self.removeAllChildren()
}

VC Performance

var scene: DrawingScene?

override func viewDidLoad(){
    let skView = self.view as! SKView
    skView.ignoresSiblingOrder = true
    scene = DrawingScene(size: skView.frame.size)
    scene?.scaleMode = .aspectFill
    scene?.backgroundColor = UIColor.white
    drawingNameLabel.text = self.currentDrawing?.name!
    scene?.currentDrawing = self.currentDrawing!

    scene?.drawingViewManager = self

    skView.presentScene(scene)
}

override func viewDidDisappear(_ animated: Bool) {
    if let view = self.view as? SKView{
        self.scene = nil //This is the line that actually got the scene to call denit.
        view.presentScene(nil)
    }
}
+4
1

, , , .

  • , , .
  • . , , . , .
  • ,
  • , , , .

1.

Xcode SpriteKit.

Enemy.swift

import SpriteKit

class Enemy: SKNode {
    private let data = Array(0...1_000_000) // just to make the node more memory consuming
    var friend: Enemy?

    override init() {
        super.init()
        print("Enemy init")
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    deinit {
        print("Enemy deinit")
    }
}

Scene.swift

import SpriteKit

class GameScene: SKScene {

    override init(size: CGSize) {
        super.init(size: size)
        print("Scene init")
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        print("Scene init")
    }

    override func didMove(to view: SKView) {
        let enemy0 = Enemy()
        let enemy1 = Enemy()

        addChild(enemy0)
        addChild(enemy1)
    }

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        let newScene = GameScene(size: self.size)
        self.view?.presentScene(newScene)
    }

    deinit {
        print("Scene deinit")
    }
}

, .

.

Scene init Enemy init Enemy init

, 3 .

Scene init Enemy init Enemy init Scene init Enemy init Enemy init Scene deinit Enemy deinit Enemy deinit

, 2 ( 4, 5, 6). , ( 7), 2 ( 8 9).

, 3 . , .

Xcode, , .

enter image description here

2.

didMove Scene.swift,

override func didMove(to view: SKView) {
    let enemy0 = Enemy()
    let enemy1 = Enemy()

    // ☠️☠️☠️ this is a scary strong retain cycle ☠️☠️☠️
    enemy0.friend = enemy1
    enemy1.friend = enemy0
    // **************************************************

    addChild(enemy0)
    addChild(enemy1)
}

, 1.

.

,

Scene init Enemy init Enemy init Scene init Enemy init Enemy init Scene deinit

, , () .

Xcode Memory

enter image description here

, .

3.

, , ( 1 ). ?

"" Xcode ( ).

enter image description here

Transfer .

Leak Checks

enter image description here

, , , .

4.

. . Instruments, ...

enter image description here

.

.

enter image description here

, 8 Enemy.

Cycles and Root and Instrument

enter image description here

!

, 4 ( 8 , ).

5.

, , - Enemy, .

friend weak.

Enemy.

class Enemy: SKNode {
    private let data = Array(0...1_000_000)
    weak var friend: Enemy?
    ... 

, , .

+6

Source: https://habr.com/ru/post/1690294/


All Articles