为什么重复创建和删除SKShapeNode和SKNode会导致内存泄漏?

时间:2013-11-29 19:31:54

标签: ios objective-c memory-leaks sprite-kit cgpath

使用Xcode附带的sprite kit模板,我将场景修改为:

#import "MyScene.h"

@interface MyScene ()
@property (nonatomic,strong)SKNode *floor;
@end

@implementation MyScene

-(id)initWithSize:(CGSize)size {    
    if (self = [super initWithSize:size]) {
        /* Setup your scene here */
    }
    return self;
}

-(void)update:(CFTimeInterval)currentTime {
    /* Called before each frame is rendered */
    [self removeAllChildren];
    self.floor = nil;
    self.floor = [SKNode node];

    CGMutablePathRef path = CGPathCreateMutable();
    CGPathMoveToPoint(path, nil, 0, 10);

    for(int i = 2; i<self.frame.size.width; i+=2)
    {
        CGPathAddLineToPoint(path, nil, i, 10);
    }

    self.floor.physicsBody = [SKPhysicsBody bodyWithEdgeChainFromPath:path];
    SKShapeNode *shape = [SKShapeNode node];
    shape.path = path;
    shape.strokeColor = [UIColor redColor];

    [self.floor addChild:shape];
    [self addChild:self.floor];

    CGPathRelease(path); 
}

@end

该应用程序似乎继续使用更多内存,直到它挂起或崩溃(达到约180MB后)。使用泄漏和分配工具,我发现了以下内容:

泄漏: Screenshot of Leaks window 分配: Screenshot of Allocations window

从图像中可以看出,有大量使用内存的Malloc调用。我不直接调用Malloc - 似乎这些调用是由SpriteKit完成的。同样,存在许多内存泄漏,这似乎也是由于SKShapeNode,SKNode或其他Sprite Kit对象造成的。

我如何解决或解决此内存(泄漏)问题?我必须每帧创建SKShapeNodes和SKNodes。这段代码只是用来说明问题的一个例子 - 我的实际项目使用动态生成的路径要复杂得多(不像本例中那样静态)。

4 个答案:

答案 0 :(得分:13)

这是精灵工具包中的一个错误。问题不仅在于SKShapeNode,还在于SKPhysicsBody。

使用CGPath创建物理主体或形状会导致内存泄漏。 您可以通过注释物理主体或形状以及运行具有泄漏,分配和内存监视器的仪器来验证这一点。

即使你正确地释放了路径,sprite kit也不在内部。你无能为力!

启动仪器,观察内存增长! XD

编辑:iOS 7.0中存在此错误。我是不是已经修复了7.1或更高版本,因为我因为这个bug而停止使用SpriteKit。可以通过简单测试来验证它是否已修复。

答案 1 :(得分:2)

我在阅读另一篇文章时意识到了这个问题。我稍微弄乱了SKShapeNode,确实验证了这里指出的内存泄漏问题。

在这样做的时候,我有了一个想法......

不是一个新想法,更多是一个改变用途的想法。这个奇妙的想法实际上允许我使用SKShapeNodes来表达我的内心:)

<强>池

是的......我刚创建了一个SKShapeNodes池,我根据需要重用了它。有什么区别使得:)

您只需在需要时重新定义路径,使用返回游泳池完成后,它将等待您以后再次玩游戏。

NSMutableArray被叫池中创建一个ivar或属性SKScene,并在初始化SKScene时创建它。您可以在初始化期间使用形状节点填充数组,也可以根据需要创建它们。

这是我为从池中获取新节点而创建的快速方法:

-(SKShapeNode *)getShapeNode
{
    if (pool.count > 0)
    {
        SKShapeNode *shape = pool[0];
        [pool removeObject:shape];
        return shape;
    }

    // if there is not any nodes left in the pool, create a new one to return
    SKShapeNode *shape = [SKShapeNode node];

    return shape;
}

因此,无论你在场景中需要SKShapeNode,你都可以这样做:

SKShapeNode *shape = [self getShapeNode];
// do whatever you need to do with the instance

完成使用shape节点后,只需将其返回到池并将路径设置为。例如:

[pool addObject:shape];
[shape removeFromParent];
shape.path = NULL;

我知道这是一种解决方法而不是一个理想的解决方案,但对于任何想要使用大量SKShapeNodes而不是流失内存的人来说,这肯定是一种非常可行的解决方法。

答案 2 :(得分:2)

我正在使用iOS 7.1.1并遇到同样的问题。但是,通过在从父项中删除形状之前将SKShapeNode的path属性设置为nil确实解决了这个问题 - 不再有泄漏。

答案 3 :(得分:0)

我遇到了同样的问题。

Scene添加了一个复合节点(SKShape和SKSprite)然后我从场景中删除了这个节点并再次添加(我泄漏了两个节点)。

从场景中删除

后,我的泄漏被重新组合节点修复