Objective c 在GLKViewController运行循环中创建自动释放对象会导致malloc错误

Objective c 在GLKViewController运行循环中创建自动释放对象会导致malloc错误,objective-c,glkit,Objective C,Glkit,我目前正在使用GLKit做一些OpenGL绘图。我创建了一个普通的UIViewController,然后在容器中添加了一个GLKViewController子类来进行绘图。虽然一开始一切运行正常,但如果我让程序运行一段时间(可能15-30分钟),最终它会崩溃,并给出以下错误 malloc: *** mmap(size=2097152) failed (error code=12) *** error: can't allocate region *** set a breakpoint in m

我目前正在使用GLKit做一些OpenGL绘图。我创建了一个普通的UIViewController,然后在容器中添加了一个GLKViewController子类来进行绘图。虽然一开始一切运行正常,但如果我让程序运行一段时间(可能15-30分钟),最终它会崩溃,并给出以下错误

malloc: *** mmap(size=2097152) failed (error code=12)
*** error: can't allocate region
*** set a breakpoint in malloc_error_break to debug
所以我打开了malloc\u error\u break断点,堆栈跟踪指向以下代码

-(NSArray*)meshes:(NSArray *)meshes sortedFromFrontToBack:(BOOL)sortedFromFrontToBack
{
    NSMutableArray *sortedMeshes = meshes.mutableCopy;
    [sortedMeshes sortUsingComparator:^NSComparisonResult(id obj1, id obj2) {
        DSNode *mesh1 = obj1;
        DSNode *mesh2 = obj2;
        GLKVector3 depth1 = isnan(mesh1.boundingSphere.radius) ? mesh1.transformationState.position : mesh1.boundingSphere.center;
        GLKVector3 depth2 = isnan(mesh2.boundingSphere.radius) ? mesh2.transformationState.position : mesh2.boundingSphere.center;

        GLKMatrix4 mesh1ToCameraSpace = [mesh1 nodeToOtherNodeTransform:self];
        GLKMatrix4 mesh2ToCameraSpace = [mesh2 nodeToOtherNodeTransform:self];

        GLKVector3 depth1InCameraSpace = GLKMatrix4MultiplyVector3WithTranslation(mesh1ToCameraSpace, depth1);
        GLKVector3 depth2InCameraSpace = GLKMatrix4MultiplyVector3WithTranslation(mesh2ToCameraSpace, depth2);


        NSNumber *n1 = [NSNumber numberWithFloat:depth1InCameraSpace.z];
        NSNumber *n2 = [NSNumber numberWithFloat:depth2InCameraSpace.z]; /* Breakpoint triggered here */

        if(sortedFromFrontToBack)
        {
            return [n2 compare:n1];
        }
        return [n1 compare:n2];
    }];

    return sortedMeshes;
}
正如我所评论的,[NSNumber numberWithFloat:]调用抛出malloc错误。从我的GLKViewController的drawInRect方法中,每个帧调用一次此方法。本质上,我有一个类,它跟踪我的相机和将由OpenGL绘制的网格,并在绘制它们之前,在相机空间中对它们进行排序,从前到后为不透明网格排序,或从后到前为透明网格排序

- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect
{
    glClearColor(self.clearColor.r, self.clearColor.g, self.clearColor.b, self.clearColor.a);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    DSDirector *director = [DSDirector sharedDirector];

    for(DSMesh *mesh in director.opaqueMeshes)
    {
        [mesh draw];
    }

    /* The director class keeps track of my scene's cameras and meshes and calls the above method to return the scene's transparent meshes properly sorted */
    for(DSMesh *mesh in director.transparentMeshes) 
    {
        [mesh draw];
    }
}

从我所读到的内容来看,自动释放池应该在每次运行循环结束时耗尽,因此我不认为在每帧创建一组自动释放对象是一个问题,它们应该在每帧都被刷新。我已经分析了我的程序,检查了是否有泄漏,但没有发现任何泄漏,我也在使用ARC,这应该可以将风险降至最低。当我对其进行分析时,活动字节总数从未发生变化,尽管总字节增长非常快,并且没有发现泄漏。此外,我还收到了“记忆警告”永不开火。我被难住了。

关于
NSNumber
创建的某些东西闻起来不对劲,是您的malloc错误的原因。用仪器测试可能有助于找到真正的罪魁祸首

然而,你正在做两件你不需要做的事情,所以消除它们可能有助于解决你的问题

首先,您不需要将
float
s包装在NSNumber中进行比较。基本的比较运算符和数学运算符工作正常,不需要额外的时间或内存来创建对象:

if (depth1InCameraSpace.z < depth2InCameraSpace.z)
    return NSOrderedAscending;
else if (depth1InCameraSpace.z > depth2InCameraSpace.z)
    return NSOrderedDescending;
else
    return NSOrderedSame;
if(depth1InCameraSpace.zdepth2InCameraSpace.z)
退而求其次;
其他的
返回指定名称;

其次,GPU硬件在iOS设备上实现的基于分片的延迟渲染策略有其自身的隐藏面移除优化功能——将不透明几何体前后排序是多余的,因此它所做的只是浪费CPU时间。(在中有一个很好的解释。)你仍然应该对半透明几何体进行前后排序(并在不透明几何体之后绘制),以便进行适当的混合。

所以,我想我已经知道了发生了什么。在之前的某个时候,我启用了NSZombies,但后来忘记了它,所以我希望解除分配的所有对象实际上仍然挂在那里。在仪器中进行分析时,僵尸不能被视为活动的,这就是为什么我无法理解为什么在活动字节数没有增加的情况下,我似乎内存不足。然而,当我升级到XCode 5时,新的内存量表显示我正在快速积累内存,然后当我进入仪器时,泄漏被一条警告所掩盖,该警告说,由于启用了NSZombies,它将无法正常工作。所以,我禁用了僵尸,现在我的内存使用保持不变,就像我预期的那样

嗯,看来你是对的,自动释放的对象不是问题所在。处理好你指出的那些事情,我仍然会遇到malloc错误,只是在不同的地方发生了中断。这一次,我对GLKVector3属性进行了一些手动KVO,堆栈跟踪以didChangeValueForKey:行结束,并出现了完全相同的malloc mmap错误。因为这看起来像是内存问题,我已经研究了仪器中的分配/泄漏,一切看起来都很好,没有泄漏,活动字节的数量永远不会增长,只是不知道从那里去哪里。