在NSMutableArray / NSArray中保存像素数据;记忆问题

时间:2013-05-06 10:57:38

标签: iphone ios cocos2d-iphone box2d

我正在尝试保存有关对象内部像素的基本信息。基本上,(1)像素是否清晰,以及(2)像素是否在我定义的表面边缘上。我正在使用以下类来定义对象:

@interface PixelInfo : NSObject
@property (nonatomic, assign) BOOL isClear;
@property (nonatomic, assign) BOOL isEdge;
@end

但是,我遇到了内存不足的问题。我正在使用此对象来跟踪具有可破坏环境的游戏中像素的状态。问题可能是对于iPad视网膜大小的图像(2048 x 1536 = 300万像素),我创建了300万这些对象,似乎分配了数百MB的内存,并导致iPhone设备强制退出到期低内存问题。

查看iPhone设备内的日志,我收到以下信息:

Name     rpages     recent_max     [reason]             (state)       
MyApp    166400     166400         [per-process-limit]  (frontmost) (resume)

使用Instruments Allocations工具,我看到随着时间的推移,分配给PixelInfo对象的数百MB内存,直到最终iPhone设备强制退出。

基于此,我猜我可能不应该像这样持有像素信息。我也怀疑仪器分配表明该设备需要数百MB的内存才能实现这一目标。其他地方可能会出现问题,但我似乎无法确定它。

我觉得需要跟踪所有像素的状态。我正在使用此像素信息来跟踪我破坏环境时的图像状态(即,将像素信息isClear属性设置为YES,将isEdge属性设置为NO),然后重新计算受影响的环境部分的新边缘。

以下是我的主要问题:

  1. 我试图在数组中容纳300万个对象是不是很糟糕?
  2. 低内存显然是一个问题(使用Instruments Allocations工具看到),但是这些300万个对象需要使用数百MB内存还是其他东西可能导致问题?这是正确的吗? LI>

    关于如何进一步调试这种情况的任何想法或指示都会非常有帮助。提前谢谢。

    - 只是为了附加上下文(如果相关),这就是我从纹理中读取和存储像素信息的方式(使用一些cocos2d类):

    unsigned char data[4];
    
    // create texture to read pixel data from
    CCRenderTexture *renderTexture = [[CCRenderTexture alloc] initWithWidth:widthInPoints
                                                                     height:heightInPoints
                                                                pixelFormat:kCCTexture2DPixelFormat_RGBA8888];
    [renderTexture beginWithClear:1 g:1 b:1 a:0];
    
    // self.view is a CCSprite object and the visit method draws it to the texture so I can read the pixels
    [self.view visit];
    
    for (int i = 0; i < heightInPixels; ++i) {
        for (int j = 0; j < widthInPixels; ++j) {
    
            // read pixel data
            CGPoint pixelPoint = ccp(j, i);
            glReadPixels(pixelPoint.x, pixelPoint.y, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, data);
    
            // store pixel data in PixelInfo object; read alpha value in data
            PixelInfo *pixelInfo = [[PixelInfo alloc] init];
            pixelInfo.isClear = [self _isPixelClear:data];
    
            // add object to _pixelData array (NSMutableArray object)
            [_pixelData addObject:pixelInfo];
            [pixelInfo release];            
        }
    }
    
    // release texture
    [renderTexture end];
    [renderTexture release];
    

3 个答案:

答案 0 :(得分:0)

减少内存使用量,使用两个布尔数组而不是包含两个布尔值的对象实例的数组

答案 1 :(得分:0)

问题不在于您在NSArray中存储了300万个PixelInfo对象。 (300万*(4 + 1 + 1)字节,假设NSObject.isa为4个字节,BOOL为1个字节,仅为18 MB)。

至少从您发布的代码中可以看出问题是您只将PixelInfo对象添加到NSArray,但从不释放它们。如果为每个渲染帧添加300万个对象(30fps),则最终可能会每秒分配540MB(18MB * 30)的内​​存。您可以看到这可能会很快导致您看到的内存问题。

在不了解太多细节的情况下,一个改进的建议是创建单个数组的短路并更新适当的值这个数组,而不是连续创建新对象并存储它们。

为了说明:

short *pixelInfo = (short *) calloc(1, sizeof(short) * heightInPixels * widthInPixels); // use calloc to zero-fill the bytes
...
pixelInfo[i*heightInPixels+j] |= [self _isPixelClear: data]; // set isClear
{{1} } pixelInfo[i*heightInPixels+j] |= [self _isPixelEdge: data] << 1; // set isEdge
pixelInfo[i*heightInPixels+j] & 0x1; // isClear set?

当然,使用这种方法,如果此信息确实存在,则需要清除帧间的像素信息不坚持跨框架。

如果您能够更详细地阐述您的需求,可能会出现更具体/更好的建议。

答案 2 :(得分:0)

使用位数组。 Michael Dipperstein的一个这样的实现可以是found here。 C版本包含在Kobold2DKoboldTouch中。