我有一个SKScene
,这是我的2D游戏的世界。它就像玩家可以探索的社区。附近有很多房子。玩家可以自由进出房屋。当玩家进入房屋时,我打电话给skView.presentScene(newHouse)
以将房屋内部呈现为新场景。当玩家离开房子时,我打电话给skView.presentScene(overworld)
再次呈现邻居。玩家可能会进入&他们探索邻里时多次出口。因此,邻居场景和房屋场景的新实例被多次呈现。
问题在于每次我呈现一个房子场景时,记忆中都会出现尖峰。这是预料到的,因为我们正在装载一个新的房子场景。但是当我退出房屋场景并返回邻居场景时,内存使用量不会下降。我通过一次又一次地进入并退出房屋来测试这一点。每次进入房屋时,内存使用量都会增加(~2 MB)。最终,内存使用量变得非常大,游戏开始丢帧(但只在室内场景中,而不是在邻居场景中),最终变得无法播放。
在使用SpriteKit时,我认为最佳做法是使用presentScene将玩家转换为一个截然不同的领域"游戏世界(例如不同的级别),这是我相信我在这里做的事情。我还以为你不应该采取任何行动来卸载"加载然后转换到新场景时的旧场景。实际上,当您呈现新场景时,SKView文档没有任何方法可以清除旧场景中不需要的对象。我认为你应该相信操作系统能够处理从内存中删除旧场景对象的工作。这就是为什么我只是提出新的场景而不担心占用记忆的旧场景。
我在仪器中分析了应用程序以检查内存泄漏(此时仪器仍然有点过头)。我确实发现了一些看起来非常小的内存泄漏,但是没有任何泄漏似乎直接导致每次我呈现一个新的房子场景时发生的大而一致的内存峰值。
我相信我正在通过展示新场景并让操作系统处理清理旧场景的工作来采取正确的方法。但也许我在我的应用程序设计中犯了一个错误,导致了这个内存问题。当我呈现一个新的房子场景时,我将一些信息从邻居场景传递到新房子场景。这些信息与房屋的外观(颜色,纹理,内容等)有关,这是必要的,因为房屋是程序生成的:每个房屋都是独一无二的。当我回到附近的场景时,我将一些信息从房屋场景传递到邻居场景。但也许我在场景之间传递信息的方式无意中导致对象被保留在内存中。如果是这样,我该怎么做以确保不会发生这种情况?当我呈现一个新场景时,是否应该运行一些代码来清除内存中不需要的对象?
我确实注意到SKScene文档有几种与呈现场景相关的方法:sceneDidLoad()
,willMove(from:)
和didMove(to:)
。这让我想知道当我在不同的场景之间转换时,我是否应该以某种方式使用这些方法来尝试从内存中清除不需要的对象。
可能是我的应用程序架构很糟糕(它已经给我带来了其他问题)。如果是这样,那么解决方案将首先通过改进我的应用程序架构来改进它。所以基本上,我试图确定我的坏应用程序架构是否导致此内存膨胀问题,或者原因是否与SpriteKit以及场景呈现方式有关。
答案 0 :(得分:3)
首先,你正确地呈现SKScene,你是对的,你应该能够相信旧场景会被清理干净。我的意思是你没有别的办法让它发布。
现在有了这样说,你可能已经做了一些事情来创建循环引用。希望这些检查能够帮助您追踪它。
我一直看的第一个地方是你的球员。如果您的场景具有玩家属性且您的玩家具有场景属性,则可能会阻止场景解除分配。球员坚持现场,场景坚持球员。我怀疑这是你的情况,但值得检查。
要看第二个地方是否有其他任何具有该场景的参考或属性?一个常见问题是当您创建自己的委托方法时。如果您的播放器执行某个操作,然后将方法调用回该场景。玩家应该只对该场景有弱引用。我自己做了这个,并看到其他人在他们创建自定义委托或协议的地方做,并保持强烈的参考,而不是弱。
要查看的第三个位置是代码中您称之为self的任何位置。这在SKActions的运行块中很常见。您可能有一个动作调用场景中的方法,并且您可能在该SKAction的场景上拥有属性。该动作由于运行块而引用场景,并且场景具有对动作的引用。因此,寻找自我并查看该对象是否是该场景中的属性。
希望这可以帮助您追踪它。我知道追踪这样的漏洞可能令人沮丧,这些都是我过去看到的常见问题。