【问题标题】:How to free memory when moving between SpriteKit scenes在 SpriteKit 场景之间移动时如何释放内存
【发布时间】:2015-08-10 15:32:29
【问题描述】:

我制作了一个包含 10 个不同场景的 spritekit 游戏,其中一个基本场景指向每个场景。当我进出每个场景时,内存会不断增加,假设是由于纹理缓存,如前所述。

问题是内存不断上升到 300 MB,在弱设备中,它在 3-4 个场景后崩溃。我尝试使用清理功能“释放”内存:

- (void)willMoveFromView:(SKView *)view {

    [self.children enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
        SKNode* child = obj;
        [child removeAllActions];
    }];

    [self removeAllChildren];       
}

但是,这无济于事。任何想法如何解决这个问题?

这是我的主要(也是唯一的)ViewController:

- (void)viewDidLoad
{
    [super viewDidLoad];

    // Configure the view.
    SKView * skView = (SKView *)self.view;
//    skView.showsFPS = YES;
    skView.showsNodeCount = YES;

    /* Sprite Kit applies additional optimizations to improve rendering performance */
    skView.ignoresSiblingOrder = YES;

    // Create and configure the scene.
    MainMenu *scene = [MainMenu sceneWithSize: self.view.bounds.size];
    scene.scaleMode = SKSceneScaleModeAspectFill;

    // Present the scene.
    [skView presentScene:scene];
}

我切换到场景代码:

- (void)switchToRoom
{
    SKTransition *transition = [SKTransition fadeWithColor:[UIColor whiteColor] duration:0.5];

    SKScene * scene = [[RoomScene alloc] initWithSize:self.size];

    [self.view presentScene:scene transition:transition];

}

更新:

经过 3 天的挣扎后,我发现我的不良做法是使用“窗帘”风格的动画在场景之间导航。这种方法的问题是“幕布”是屏幕大小,大约 30 个纹理的幕布图集是巨大的,可能是什么导致内存运行如此之高,我不知道为什么会导致泄漏类似的行为,但是当将图集中的帧数减少到 10 左右时,我不再看到内存变得那么高,而且看起来没有泄漏。

针对这种情况的另一个不好的做法是使用“preloadTextures:textures”方法,这似乎会为这种类型的动画消耗大量内存。当我删除它时,性能变得更好。

【问题讨论】:

  • 您是否尝试过在调用 presentScene: 之前只调用该代码而不是将其放入 willMoveFromView: 中?
  • 另外,您是否添加了日志或断点以确保 willMoveFromView: 被调用?
  • 是的。它不起作用..
  • 为什么 Room 场景被初始化为 SKScene 而不是 Room 场景
  • 显然有些东西没有被释放。最简单的做法是在分配工具中加载您的应用程序,检查该场景中正在使用的对象的对象计数,并查看未释放的对象。然后你可以更深入地找到 + 和 - 保留,看看你在哪里有额外的保留或应该有另一个 -。

标签: ios7 ios8 sprite-kit


【解决方案1】:

假设 SK 会自行处理所有这些问题,前提是您有一个保留循环。但是我也遇到了这个问题。我的解决方案最终是手动将所有内容设置为零:

-(void)willMoveFromView:(SKView *)view {

    // for all arrays
    [self.myArray removeAllObjects]; // and so on...

    // for all objects
    self.worldNode = nil;
    self.player = nil; // and so on...
}

正如您已经说过的,由于缓存会有所增加,但您应该在某个时候进行调整。如果这不起作用,请尝试运行 Instruments 以查看是否可以发现泄漏。

【讨论】:

  • 为节点设置“nil”不会从缓存中释放预加载的纹理。
  • sangony 是正确的,如果您希望从内存中释放纹理删除生成这些纹理的纹理图集删除纹理并不能帮助您删除和添加纹理集,这取决于您的要求,这将解决您的问题
  • @Yuvals - 将对象设置为 nil 不会自动释放任何东西,但它会在 SK 认为合适时释放任何东西。你说你跑了仪器,没有泄漏。您还说您的应用程序在 3 到 4 次场景更改后崩溃。从表面上看,您要么通过场景转换保留对象,要么您的代码存在逻辑错误并且创建了太多消耗内存的对象。
  • @sangony 我认为情况并非如此 - 看起来问题是使用大量纹理图集的结果。但是,我希望 spritekit 释放它们并且在内存过度杀伤之前不会缓存
猜你喜欢
  • 1970-01-01
  • 2016-02-11
  • 2017-08-06
  • 2023-03-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-12-07
相关资源
最近更新 更多