I have a memory corruption error (I suspect), which is resulting in a program crash after specific UI actions. This is a Cocoa Objective-C application and does not use GC.
我有一个内存损坏错误(我怀疑),这导致程序在特定UI操作后崩溃。这是一个Cocoa Objective-C应用程序,不使用GC。
After many hours of debugging, I found a possible reason for the crash:
经过几个小时的调试,我发现了崩溃的可能原因:
DiscSelectPopup *popupSelect = [[DiscSelectPopup alloc] initWithDataList:dataList count:count];
NSInteger result = [NSApp runModalForWindow:popupSelect.window];
The above popup routine is executed from a secondary thread. This thread is created and started every time the user clicks on a button. So, we can have several modal popup show up simultaneously.
上面的弹出例程是从辅助线程执行的。每次用户单击按钮时,都会创建并启动此线程。所以,我们可以同时显示几个模态弹出窗口。
When I run the program in debug mode with MallocStackLogging=1
and MallocStackLoggingNoCompact=1
, it prints a malloc error log message at the runModalForWindow:
call (but not always).
当我在调试模式下使用MallocStackLogging = 1和MallocStackLoggingNoCompact = 1运行程序时,它会在runModalForWindow:调用时打印malloc错误日志消息(但并非总是如此)。
malloc: *** error for object 0xbc65840: double free
.....
malloc: *** error for object 0xbc547e0: pointer being freed was not allocated
Is it really bad to use runModalForWindow:
from a secondary thread?
Could it be the reason for the crash?
使用runModalForWindow是非常糟糕的:来自辅助线程?可能是撞车的原因吗?
2 个解决方案
#1
6
Is it really bad to use
runModalForWindow
from the secondary thread?从辅助线程使用runModalForWindow真的很糟糕吗?
Yes. UI stuff needs to happen on the main thread.
是。 UI东西需要在主线程上发生。
You also shouldn't use runModalForWindow:
unless you specifically want to block all of the other windows in your application (essentially freezing your app except for that window). Just show the window. If you want to block a specific window (or your app is single-window), begin it as a sheet.
您也不应该使用runModalForWindow:除非您特别想要阻止应用程序中的所有其他窗口(基本上冻结您的应用程序除了该窗口)。只是显示窗口。如果要阻止特定窗口(或者您的应用程序是单窗口),请将其作为工作表开始。
Edit: Looking again at the question, this caught my eye:
编辑:再看一下这个问题,这引起了我的注意:
The above popup routine is executed from a secondary thread.
上面的弹出例程是从辅助线程执行的。
Don't do that. To show a window, just show it. Receive the action message from the button on the main thread, and then do only the actual work—if anything—on a secondary thread.
不要那样做。要显示一个窗口,只需显示它。从主线程上的按钮接收操作消息,然后仅在辅助线程上执行实际工作(如果有的话)。
Note that showing the window will not block any other windows or anything else you're doing unless you specifically make it do so (i.e., use runModalForWindow:
). If you show the window in the normal way, all your windows continue to work normally. Any timers and observers and similar things you've scheduled on the main thread also continue to work. You don't need to create threads or do anything else special for this; it all just works by default.
请注意,显示窗口不会阻止任何其他窗口或您正在做的任何其他操作,除非您特别指出(即使用runModalForWindow :)。如果以正常方式显示窗口,则所有窗口都将继续正常工作。您在主线程上安排的任何计时器和观察者以及类似的东西也会继续工作。您不需要为此创建线程或执行任何其他特殊操作;一切都只是默认工作。
If the work that you'll eventually do may take a non-trivial amount of time, then you should put that on a secondary thread, only when it comes time to do it. You should also look into whether or not it'd be easier or better to construct as operation objects or blocks than as raw threads. It probably will.
如果你最终要完成的工作可能需要花费很多时间,那么你应该把它放在一个辅助线程上,只有当它到了时候。您还应该研究构造操作对象或块是否比原始线程更容易或更好。它可能会。
#2
-3
Using valgrind memcheck, I concluded that the secondary thread runModalForWindow:
calls are not directly connected with the memory corruption problem.
使用valgrind memcheck,我得出结论,辅助线程runModalForWindow:调用与内存损坏问题没有直接关联。
Yes, it is bad coding to manipulate UI components from non-main threads but such behavior alone cannot crash the program.
是的,从非主线程操作UI组件是不好的编码,但仅此类行为不会使程序崩溃。
The malloc error message in the question was due to the mistakenly double released popup window object.
问题中的malloc错误消息是由于错误地双重释放的弹出窗口对象。
By the way, real cause of the memory corruption was the mismatched malloc/free call (freeing not malloced memory pointer).
顺便说一下,内存损坏的真正原因是不匹配的malloc / free调用(释放没有malloced内存指针)。
#1
6
Is it really bad to use
runModalForWindow
from the secondary thread?从辅助线程使用runModalForWindow真的很糟糕吗?
Yes. UI stuff needs to happen on the main thread.
是。 UI东西需要在主线程上发生。
You also shouldn't use runModalForWindow:
unless you specifically want to block all of the other windows in your application (essentially freezing your app except for that window). Just show the window. If you want to block a specific window (or your app is single-window), begin it as a sheet.
您也不应该使用runModalForWindow:除非您特别想要阻止应用程序中的所有其他窗口(基本上冻结您的应用程序除了该窗口)。只是显示窗口。如果要阻止特定窗口(或者您的应用程序是单窗口),请将其作为工作表开始。
Edit: Looking again at the question, this caught my eye:
编辑:再看一下这个问题,这引起了我的注意:
The above popup routine is executed from a secondary thread.
上面的弹出例程是从辅助线程执行的。
Don't do that. To show a window, just show it. Receive the action message from the button on the main thread, and then do only the actual work—if anything—on a secondary thread.
不要那样做。要显示一个窗口,只需显示它。从主线程上的按钮接收操作消息,然后仅在辅助线程上执行实际工作(如果有的话)。
Note that showing the window will not block any other windows or anything else you're doing unless you specifically make it do so (i.e., use runModalForWindow:
). If you show the window in the normal way, all your windows continue to work normally. Any timers and observers and similar things you've scheduled on the main thread also continue to work. You don't need to create threads or do anything else special for this; it all just works by default.
请注意,显示窗口不会阻止任何其他窗口或您正在做的任何其他操作,除非您特别指出(即使用runModalForWindow :)。如果以正常方式显示窗口,则所有窗口都将继续正常工作。您在主线程上安排的任何计时器和观察者以及类似的东西也会继续工作。您不需要为此创建线程或执行任何其他特殊操作;一切都只是默认工作。
If the work that you'll eventually do may take a non-trivial amount of time, then you should put that on a secondary thread, only when it comes time to do it. You should also look into whether or not it'd be easier or better to construct as operation objects or blocks than as raw threads. It probably will.
如果你最终要完成的工作可能需要花费很多时间,那么你应该把它放在一个辅助线程上,只有当它到了时候。您还应该研究构造操作对象或块是否比原始线程更容易或更好。它可能会。
#2
-3
Using valgrind memcheck, I concluded that the secondary thread runModalForWindow:
calls are not directly connected with the memory corruption problem.
使用valgrind memcheck,我得出结论,辅助线程runModalForWindow:调用与内存损坏问题没有直接关联。
Yes, it is bad coding to manipulate UI components from non-main threads but such behavior alone cannot crash the program.
是的,从非主线程操作UI组件是不好的编码,但仅此类行为不会使程序崩溃。
The malloc error message in the question was due to the mistakenly double released popup window object.
问题中的malloc错误消息是由于错误地双重释放的弹出窗口对象。
By the way, real cause of the memory corruption was the mismatched malloc/free call (freeing not malloced memory pointer).
顺便说一下,内存损坏的真正原因是不匹配的malloc / free调用(释放没有malloced内存指针)。