0

我正在尝试保存有关对象内部像素的基本信息。基本上,(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 工具,我看到随着时间的推移,数百 MB 的内存被分配给 PixelInfo 对象,直到最终,iPhone 设备强制退出。

基于此,我猜也许我不应该持有这样的像素信息。我也怀疑 Instruments Allocations 显示设备需要数百 MB 内存才能完成此操作。其他地方可能出了问题,但我似乎无法确定。

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

以下是我的主要问题:

  1. 我试图在一个数组中保存 300 万个对象是不是很糟糕?
  2. 内存不足显然是一个问题(使用 Instruments Allocations 工具查看),但是这 300 万个对象需要使用数百 MB 的内存是否正确,或者是否有其他原因导致了问题?

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

- 只是为了附加上下文(如果相关),这就是我从纹理读取和存储像素信息的方式(使用一些 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];
4

3 回答 3

0

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

于 2013-05-06T21:58:24.147 回答
0

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

于 2013-05-06T11:11:25.047 回答
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
pixelInfo[i*heightInPixels+j] |= [self _isPixelEdge: data] << 1; // set isEdge
pixelInfo[i*heightInPixels+j] & 0x1; // isClear set?
(pixelInfo[i*heightInPixels+j] >> 1) & 0x1; // isEdge set?

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

如果您可以更详细地表达您的需求,则可能会提出更具体/更好的建议。

于 2013-05-06T11:44:35.680 回答