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

时间:2013-09-05 17:24:33

标签: 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 malloc_error_break to debug

所以我打开了malloc_error_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,这应该将风险降至最低。当我对它进行分析时,实时字节总数永远不会出现,尽管整体字节上升得非常快,并且没有发现泄漏。另外,didReceiveMemoryWarning永远不会触发。我很难过。

2 个答案:

答案 0 :(得分:0)

NSNumber创建导致malloc错误的原因有些不对劲。用仪器测试可能有助于找到真正的罪魁祸首。

但是,你正在做两件你不需要的事情,所以有一些机会可以消除它们对你的问题有所帮助。

首先,您不需要在NSNumber中包装float来比较它们。基本比较和数学运算符工作得很好,并且不需要额外的时间或内存来创建对象:

if (depth1InCameraSpace.z < depth2InCameraSpace.z)
    return NSOrderedAscending;
else if (depth1InCameraSpace.z > depth2InCameraSpace.z)
    return NSOrderedDescending;
else
    return NSOrderedSame;

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

答案 1 :(得分:0)

所以,我想我已经弄清楚发生了什么。在之前的某个时刻,我已经启用了NSZombies然后忘了它,所以我期望被解除分配的所有物体实际上仍然在闲逛。当在仪器中进行分析时,僵尸不能被视为现场,这就是为什么我无法弄清楚为什么当实时字节数没有攀升时我看起来似乎内存不足的原因。然而,当我升级到XCode 5时,新的内存指示器显示我正在迅速占用内存,然后当我放入仪器时,Leaks被一个警告所掩盖,该警告声称自NSZombies启用后它将无法正常工作。所以,我禁用了僵尸,现在我的内存使用率保持不变,就像我预期的那样。