导航时iPhone OpenGL应用程序随机崩溃

时间:2022-09-07 09:12:44

I'm working on a iPhone application which is hybrid OpenGL ES and regular iPhone UI. This means there is an EAGLView greeting the user, then some regular UIViews that gets pushed over it (there is a UINavigationController as root controller).

我正在开发一个混合OpenGL ES和常规iPhone UI的iPhone应用程序。这意味着有一个EAGLView问候用户,然后一些常规的UIViews被推过它(有一个UINavigationController作为根控制器)。

I've got a random (but very frequent) crash when navigating back from a subview. Here is a (...censored...) stack trace, from a Release build, but it crashes just the same in Debug.

从子视图导航回来时,我有一个随机(但非常频繁)的崩溃。这是一个(...审查的......)堆栈跟踪,来自Release版本,但它在Debug中崩溃了。

#0  0x006863d0 in GetFBOBuffers ()
#1  0x00660120 in TerminateScene ()
#2  0x00660314 in FlushScene ()
#3  0x00660cd4 in FlushHW ()
#4  0x0066a6a0 in GLESPresentView ()
#5  0x323533a4 in -[EAGLContext presentRenderbuffer:] ()
#6  0x000026c0 in -[EAGLView presentFramebuffer] (self=0x11ce60, _cmd=<value temporarily unavailable, due to optimizations>) at (...)/Classes/EAGLView.m:157
#7  0x00004fdc in -[(...)ViewController drawFrame] (self=<value temporarily unavailable, due to optimizations>, _cmd=<value temporarily unavailable, due to optimizations>) at (...)    ViewController.m:380
#8  0x336ebd9a in __NSFireTimer ()
#9  0x323f54c2 in CFRunLoopRunSpecific ()
#10 0x323f4c1e in CFRunLoopRunInMode ()
#11 0x335051c8 in GSEventRunModal ()
#12 0x324a6c30 in -[UIApplication _run] ()
#13 0x324a5230 in UIApplicationMain ()
#14 0x0000214c in main (argc=1, argv=0x2ffff568) at (...)/main.m:14

Here is a list of things I know:

以下列出了我所知道的事项:

  • My app doesn't get a memory warning.
  • 我的应用程序没有得到内存警告。

  • My app has no identified leak under Instruments.
  • 我的应用程序在仪器下没有发现泄漏。

  • No crash on Simulator, but sometimes a very noticeable lag.
  • 模拟器上没有崩溃,但有时会出现非常明显的延迟。

  • There is a significant amount of released data in Instruments/OpenGL/ResourceBytes just before the crash.
  • 在崩溃之前,Instruments / OpenGL / ResourceBytes中有大量已发布的数据。

  • I'm using both VBOs and vertex/texcoord/normals arrays.
  • 我正在使用VBO和vertex / texcoord / normals数组。

So I know it must be some kind of data that gets released or destroyed, but I don't know how to find which. Any tips and tricks would be appreciated ;-)

所以我知道它必须是某种被释放或销毁的数据,但我不知道如何找到它。任何提示和技巧将不胜感激;-)

UPDATE:

After setting some breakpoints, moving along the stack, poking at various variables, I've found the reason for the crash, but not yet the source.

在设置了一些断点,沿着堆栈移动,查看各种变量后,我找到了崩溃的原因,但还没有找到源。

In EAGLView, in the method presentFramebuffer where and when the crash occurs, the colorRenderBuffer ivar is 0 if I can believe gdb, even though trying to breakpoint when it's 0 doesn't seem to work.

在EAGLView中,在presentFramebuffer方法中崩溃发生的地方和时间,如果我可以相信gdb,则colorRenderBuffer ivar为0,即使尝试断点时它似乎不起作用。

It seems the deleteFrameBuffer call from layoutSubviews isn't matched by a createFramebuffer.

似乎layoutSubviews中的deleteFrameBuffer调用与createFramebuffer不匹配。

UPDATE 2:

Lots of breakpoints later... I've found a wrong situation: [EAGLView layoutSubviews] gets called in the middle of a drawFrame ! So the buffers get deleted while in use... BAM!

后来有很多断点......我发现了一个错误的情况:[EAGLView layoutSubviews]在drawFrame中被调用!因此缓冲区在使用时被删除... BAM!

Now how do I fix that?

现在我该如何解决这个问题?

4 个解决方案

#1


3  

I haven't found a 'proper' fix yet, but I've added a workaround.

我还没有找到“正确”的解决方案,但我添加了一个解决方法。

In presentFramebuffer, I set a boolean around the rendering :

在presentFramebuffer中,我在渲染周围设置了一个布尔值:

if (context)
{
    isRendering_PATCH_VARIABLE = YES;

    [EAGLContext setCurrentContext:context];

    glBindRenderbufferOES(GL_RENDERBUFFER_OES, colorRenderbuffer);

    success = [context presentRenderbuffer:GL_RENDERBUFFER_OES];

    glBindRenderbufferOES(GL_RENDERBUFFER_OES, 0);

    isRendering_PATCH_VARIABLE = NO;
}

and in deleteFramebuffer, I check this boolean:

在deleteFramebuffer中,我检查这个布尔值:

if (isRendering_PATCH_VARIABLE)
{
    NSLog(@"GOTCHA - CRASH AVOIDED");   
}

if (context && !isRendering_PATCH_VARIABLE)
{
    // ...
}

It doesn't seem to have side-effects (like broken display, etc), so I'll leave it like that for the moment.

它似乎没有副作用(比如破坏显示等),所以我暂时不会这样做。

#2


3  

Here's wild guess based on something I did recently.

基于我最近做的事情,这是一个疯狂的猜测。

What I did was break up the loading stage. I wanted to show a progress bar as I loaded up a number of resources - it's a slow process so I wanted to provide some user feedback.

我所做的是打破装载阶段。当我加载了大量资源时,我想显示一个进度条 - 这是一个缓慢的过程,所以我想提供一些用户反馈。

My first step was similar to the OpenGL ES example provided with Xcode in that I called an init on an ES?Renderer. But after that I stalled the process so I could load other resources.

我的第一步类似于Xcode提供的OpenGL ES示例,我在ES?Renderer上调用了一个init。但在那之后我停止了这个过程,所以我可以加载其他资源。

To cut a long story short, because of my re-arrangement of code the [EAGLView layoutSubviews] was never called after my initialisation. I didn't get a crash, but nothing much happened after this point.

简而言之,由于我重新安排了代码,我的初始化后从未调用[EAGLView layoutSubviews]。我没有遇到崩溃,但在此之后没有发生任何事情。

What I had to do was that after I finished initialising OpenGL's context and loading all my data, I had to manually call the [EAGLView layoutSubviews]. This seemed to fix things for me.

我必须要做的是,在我完成初始化OpenGL的上下文并加载我的所有数据之后,我不得不手动调用[EAGLView layoutSubviews]。这似乎解决了我的问题。

Maybe you need to try something similar. After you initialise your OpenGL context and data, call the [EAGLView layoutSubviews] before you get into your drawing routines. Maybe this will stop this call again reappearing in your rendering step and crashing.

也许你需要尝试类似的东西。在初始化OpenGL上下文和数据之后,在进入绘图例程之前调用[EAGLView layoutSubviews]。也许这会再次停止此调用再次出现在渲染步骤中并崩溃。

#3


1  

A stab in the dark: Your device gets low on memory, the application receives a memory warning and the controller responsible for the GL view releases the view, which is something you did not count with? Does the problem go away when you suppress the default didReceiveMemoryWarning?

在黑暗中刺伤:您的设备内存不足,应用程序收到内存警告,负责GL视图的控制器释放视图,这是您不计算的内容?当您取消默认的didReceiveMemoryWarning时,问题是否会消失?

- (void) didReceiveMemoryWarning { /* nothing we can do, sorry */ }

…or maybe you are calling OpenGL from another thread that does not have the context?

...或者你可能从另一个没有上下文的线程调用OpenGL?

#4


1  

I had this problem and used your work around for a while. What I've recently noticed, however, was that the crash only happened on an orientation change.

我有这个问题并且使用了你的工作一段时间。然而,我最近注意到的是,坠机只发生在方向改变上。

I changed my root view controller to pause the displaylink in the WillRotate... and resume it in the DidRotateFrom... delegate functions.

我更改了我的根视图控制器以暂停WillRotate中的displaylink ...并在DidRotateFrom ...委托函数中恢复它。

This fixed the problem and I don't need the hack work around anymore.

这解决了问题,我不再需要黑客工作了。

Unfortunately it does sound like your problem is slightly different but thought I'd post this just in case.

不幸的是,听起来你的问题略有不同,但我想发布这个以防万一。

#1


3  

I haven't found a 'proper' fix yet, but I've added a workaround.

我还没有找到“正确”的解决方案,但我添加了一个解决方法。

In presentFramebuffer, I set a boolean around the rendering :

在presentFramebuffer中,我在渲染周围设置了一个布尔值:

if (context)
{
    isRendering_PATCH_VARIABLE = YES;

    [EAGLContext setCurrentContext:context];

    glBindRenderbufferOES(GL_RENDERBUFFER_OES, colorRenderbuffer);

    success = [context presentRenderbuffer:GL_RENDERBUFFER_OES];

    glBindRenderbufferOES(GL_RENDERBUFFER_OES, 0);

    isRendering_PATCH_VARIABLE = NO;
}

and in deleteFramebuffer, I check this boolean:

在deleteFramebuffer中,我检查这个布尔值:

if (isRendering_PATCH_VARIABLE)
{
    NSLog(@"GOTCHA - CRASH AVOIDED");   
}

if (context && !isRendering_PATCH_VARIABLE)
{
    // ...
}

It doesn't seem to have side-effects (like broken display, etc), so I'll leave it like that for the moment.

它似乎没有副作用(比如破坏显示等),所以我暂时不会这样做。

#2


3  

Here's wild guess based on something I did recently.

基于我最近做的事情,这是一个疯狂的猜测。

What I did was break up the loading stage. I wanted to show a progress bar as I loaded up a number of resources - it's a slow process so I wanted to provide some user feedback.

我所做的是打破装载阶段。当我加载了大量资源时,我想显示一个进度条 - 这是一个缓慢的过程,所以我想提供一些用户反馈。

My first step was similar to the OpenGL ES example provided with Xcode in that I called an init on an ES?Renderer. But after that I stalled the process so I could load other resources.

我的第一步类似于Xcode提供的OpenGL ES示例,我在ES?Renderer上调用了一个init。但在那之后我停止了这个过程,所以我可以加载其他资源。

To cut a long story short, because of my re-arrangement of code the [EAGLView layoutSubviews] was never called after my initialisation. I didn't get a crash, but nothing much happened after this point.

简而言之,由于我重新安排了代码,我的初始化后从未调用[EAGLView layoutSubviews]。我没有遇到崩溃,但在此之后没有发生任何事情。

What I had to do was that after I finished initialising OpenGL's context and loading all my data, I had to manually call the [EAGLView layoutSubviews]. This seemed to fix things for me.

我必须要做的是,在我完成初始化OpenGL的上下文并加载我的所有数据之后,我不得不手动调用[EAGLView layoutSubviews]。这似乎解决了我的问题。

Maybe you need to try something similar. After you initialise your OpenGL context and data, call the [EAGLView layoutSubviews] before you get into your drawing routines. Maybe this will stop this call again reappearing in your rendering step and crashing.

也许你需要尝试类似的东西。在初始化OpenGL上下文和数据之后,在进入绘图例程之前调用[EAGLView layoutSubviews]。也许这会再次停止此调用再次出现在渲染步骤中并崩溃。

#3


1  

A stab in the dark: Your device gets low on memory, the application receives a memory warning and the controller responsible for the GL view releases the view, which is something you did not count with? Does the problem go away when you suppress the default didReceiveMemoryWarning?

在黑暗中刺伤:您的设备内存不足,应用程序收到内存警告,负责GL视图的控制器释放视图,这是您不计算的内容?当您取消默认的didReceiveMemoryWarning时,问题是否会消失?

- (void) didReceiveMemoryWarning { /* nothing we can do, sorry */ }

…or maybe you are calling OpenGL from another thread that does not have the context?

...或者你可能从另一个没有上下文的线程调用OpenGL?

#4


1  

I had this problem and used your work around for a while. What I've recently noticed, however, was that the crash only happened on an orientation change.

我有这个问题并且使用了你的工作一段时间。然而,我最近注意到的是,坠机只发生在方向改变上。

I changed my root view controller to pause the displaylink in the WillRotate... and resume it in the DidRotateFrom... delegate functions.

我更改了我的根视图控制器以暂停WillRotate中的displaylink ...并在DidRotateFrom ...委托函数中恢复它。

This fixed the problem and I don't need the hack work around anymore.

这解决了问题,我不再需要黑客工作了。

Unfortunately it does sound like your problem is slightly different but thought I'd post this just in case.

不幸的是,听起来你的问题略有不同,但我想发布这个以防万一。