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

使用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后)。 使用泄漏和分配工具,我发现了以下内容:

泄漏: Leaks窗口的屏幕截图 分配: 分配窗口的屏幕截图

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

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

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

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

即使你正确释放路径,精灵套件也不在内部。 你什么都做不了!

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

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

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

在这样做时,我有了一个想法……

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

POOLING

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

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

SKScene创建一个名为pool的ivar或属性NSMutableArray ,并在初始化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而不是流失内存的人来说,这肯定是一种非常可行的解决方法。

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

我有同样的问题。

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

从场景中删除后,我的泄漏用娱乐复合节点修复