简体   繁体   English

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

[英]Why does creating and removing SKShapeNode and SKNode repeatedly cause a memory leak?

Using the sprite kit template that comes with Xcode, I modify the scene to be as follows : 使用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

The app seems to keep using more memory, until it either hangs or crashes (after reaching about 180MB). 该应用程序似乎继续使用更多内存,直到它挂起或崩溃(达到约180MB后)。 Using the leaks and allocations tools, I have found the following: 使用泄漏和分配工具,我发现了以下内容:

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

As can be seen from the images, there are a large number of Malloc calls using memory. 从图像中可以看出,存在大量使用内存的Malloc调用。 I do not call Malloc directly - it seems these calls are made by SpriteKit. 我不直接调用Malloc - 似乎这些调用是由SpriteKit完成的。 Likewise, there are a number of memory leaks, which also seem to be due to SKShapeNode, SKNode or other Sprite Kit objects. 同样,存在许多内存泄漏,这似乎也是由于SKShapeNode,SKNode或其他Sprite Kit对象造成的。

How do I work around or solve this memory(leak) problem? 我如何解决或解决此内存(泄漏)问题? I have to create SKShapeNodes, and SKNodes every frame. 我必须每帧创建SKShapeNodes和SKNodes。 This code is just a sample to illustrate the problem - my actual project is much more complex with dynamically generated paths (not static like the one in this example). 这段代码只是用来说明问题的一个例子 - 我的实际项目使用动态生成的路径要复杂得多(不像本例中那样是静态的)。

This is a bug in sprite kit. 这是精灵工具包中的一个错误。 The problem isn't just with SKShapeNode, it is also with SKPhysicsBody. 问题不仅在于SKShapeNode,还在于SKPhysicsBody。

Creating either a physics body, or a shape, using a CGPath causes a memory leak. 使用CGPath创建物理主体或形状会导致内存泄漏。 You can verify this by commenting out either the physics body, or the shape, and running instruments with leaks, allocations and memory monitor. 您可以通过注释物理主体或形状以及运行具有泄漏,分配和内存监视器的仪器来验证这一点。

Even if you release the path properly, sprite kit doesn't internally. 即使您正确释放路径,sprite工具包也不在内部。 Nothing you can do! 你什么都做不了!

Fire up instruments, and watch the memory grow! 启动仪器,观察内存增长! XD XD

EDIT: This bug was present in iOS 7.0. 编辑:这个错误出现在iOS 7.0中。 Whether it has been fixed in 7.1 or later is not known to me as I stopped using SpriteKit because of this bug. 我是不是已经修复了7.1或更高版本,因为我因为这个bug而停止使用SpriteKit。 One can verify if it is fixed by simply testing it. 可以通过简单测试来验证它是否已修复。

I became aware of this issue while reading another post. 我在阅读另一篇文章时意识到了这个问题。 I messed around with SKShapeNode a bit and indeed verified the memory leak issue pinpointed here. SKShapeNode弄乱了SKShapeNode ,确实验证了这里指出的内存泄漏问题。

While doing that, I had an idea... 在这样做的时候,我有了一个想法......

Not really a new idea, more of a repurposed one. 不是一个新想法,更多是一个改变用途的想法。 This wonderful idea actually allowed me to use SKShapeNodes to my hearts content :) 这个奇妙的想法实际上允许我使用SKShapeNodes到我心中的内容:)

POOLING POOLING

Yep... I just created a pool of SKShapeNodes that I reused as needed. 是的......我刚创建了一个SKShapeNodes池,我根据需要重用了它。 What a difference that makes :) 有什么区别让:)

You simply redefine the path whenever needed, when done using return to your pool, and it'll be waiting there for you to play with again at a later time. 您只需在需要时重新定义路径,使用返回游泳池完成后,它将等待您稍后再次玩游戏。

Create a ivar or property NSMutableArray in your SKScene called pool and create it when you init the SKScene . SKScene创建名为pool的ivar或属性NSMutableArray ,并在初始化SKScene时创建它。 You can either populate the array with your shape nodes during init, or you can create them as needed. 您可以在init期间使用形状节点填充数组,也可以根据需要创建它们。

This is something quick method I created for grabbing a new node from the pool : 这是我为从池中获取新节点而创建的快速方法:

-(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;
}

So wherever in the scene you need a SKShapeNode you'd do this : 所以无论你在场景中需要SKShapeNode,你都会这样做:

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

When you are done using the shape node, just return it to the pool and set the path to . 完成使用shape节点后,只需将其返回到池并将路径设置为。 For example : 例如 :

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

I know it's a workaround and not an ideal solution, but certainly this is a very viable workaround for anyone wanting to use a large number of SKShapeNodes and not bleed memory. 我知道这是一种解决方法,而不是一个理想的解决方案,但对于任何想要使用大量SKShapeNodes而不是流失内存的人来说,这肯定是一种非常可行的解决方法。

I'm using iOS 7.1.1 and had the same problem. 我正在使用iOS 7.1.1并遇到了同样的问题。 However, by setting the SKShapeNode's path property to nil before removing a shape from a parent did fix this issue - no more leaks. 但是,通过在从父项中删除形状之前将SKShapeNode的path属性设置为nil确实可以解决此问题 - 不再有泄漏。

I've the same problem. 我有同样的问题。

Scene added one compound node (SKShape with SKSprite) then I removed this node from scene and added again(I got leak two nodes). 场景添加了一个复合节点(SKShape与SKSprite)然后我从场景中删除了这个节点并再次添加(我泄漏了两个节点)。

My leak is fixed with recreation compound node after remove from scene 从场景中删除后,我的泄漏用娱乐复合节点修复

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM