0

我有一个内存损坏错误(我怀疑),这导致特定 UI 操作后程序崩溃。这是一个 Cocoa Objective-C 应用程序,不使用 GC。

经过几个小时的调试,我找到了崩溃的可能原因:

DiscSelectPopup *popupSelect = [[DiscSelectPopup alloc] initWithDataList:dataList count:count];     
NSInteger result = [NSApp runModalForWindow:popupSelect.window];

上述弹出例程是从辅助线程执行的。每次用户单击按钮时都会创建并启动该线程。因此,我们可以同时显示多个模态弹出窗口。

MallocStackLogging=1当我使用and在调试模式下运行程序时MallocStackLoggingNoCompact=1,它会在调用时打印一条 malloc 错误日志消息runModalForWindow:(但并非总是如此)。

malloc: *** error for object 0xbc65840: double free
.....
malloc: *** error for object 0xbc547e0: pointer being freed was not allocated

runModalForWindow:从辅助线程使用真的很糟糕吗?
这可能是坠机的原因吗?

4

2 回答 2

6

runModalForWindow从辅助线程使用真的很糟糕吗?

是的。UI 的东西需要在主线程上发生。

runModalForWindow:除非您特别想阻止应用程序中的所有其他窗口(基本上冻结您的应用程序,除了该窗口),否则您也不应该使用。只是显示窗口。如果您想阻止特定窗口(或者您的应用程序是单窗口),请将其作为工作表开始。

编辑:再看这个问题,这引起了我的注意:

上述弹出例程是从辅助线程执行的。

不要那样做。要显示一个窗口,只需显示它。从主线程上的按钮接收操作消息,然后在辅助线程上只执行实际工作(如果有的话)。

请注意,显示该窗口不会阻止任何其他窗口或您正在执行的任何其他操作,除非您特意这样做(即使用runModalForWindow:)。如果您以正常方式显示窗口,您的所有窗口将继续正常工作。您在主线程上安排的任何计时器和观察者以及类似的东西也继续工作。您不需要为此创建线程或做任何其他特别的事情;默认情况下,这一切都正常。

如果你最终要做的工作可能需要很长时间,那么你应该把放在辅助线程上,只有在需要时才去做。您还应该研究将其构造为操作对象或块是否比作为原始线程更容易或更好。它可能会。

于 2012-04-25T15:49:09.213 回答
-3

使用 valgrind memcheck,我得出结论,辅助线程runModalForWindow:调用与内存损坏问题没有直接关系。

是的,从非主线程操作 UI 组件是一种糟糕的编码,但仅靠这种行为不会使程序崩溃。

问题中的 malloc 错误消息是由于错误地双释放弹出窗口对象。

顺便说一句,内存损坏的真正原因是不匹配的 malloc/free 调用(释放未分配的内存指针)。

于 2012-04-26T13:25:17.417 回答