0

我目前正在使用 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 永远不会触发。我难住了。

4

2 回答 2

0

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

但是,您正在做两件您不需要做的事情,因此消除它们可能有助于解决您的问题。

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

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

其次,iOS 设备上由 GPU 硬件实现的 Tile-Based Deferred Rendering 策略进行了自己的隐藏表面去除优化——从前到后排序不透明几何体是多余的,所以它所做的只是浪费 CPU 时间。(这在OpenGL ES Hardware Platform Guide for iOS中有一个不错的解释。)您仍然应该将半透明几何体排序到前面(并在不透明几何体之后绘制它)以进行适当的混合。

于 2013-09-06T21:52:46.557 回答
0

所以,我想我已经弄清楚发生了什么。在之前的某个时间点,我启用了 NSZombies,然后忘记了它,所以我希望被释放的所有对象实际上仍然在闲逛。在 Instruments 中进行分析时,不能将僵尸计算为活动的,这就是为什么我无法弄清楚为什么当活动字节数没有攀升时我似乎内存不足。然而,当我升级到 XCode 5 时,新的内存量表显示我正在快速积累内存,然后当我进入 Instruments 时,Leaks 被一个警告所掩盖,说它无法正常工作,因为 NSZombies 已启用。所以,我禁用了僵尸,现在我的内存使用量保持不变,就像我预期的那样。

于 2013-09-24T16:11:33.927 回答