我正在尝试保存有关对象内部像素的基本信息。基本上,(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),然后重新计算受影响的环境部分的新边缘。
以下是我的主要问题:
关于如何进一步调试这种情况的任何想法或指示都会非常有帮助。提前谢谢。
- 只是为了附加上下文(如果相关),这就是我从纹理中读取和存储像素信息的方式(使用一些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];
答案 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版本包含在Kobold2D和KoboldTouch中。