当系统清除内存并关闭 UIViewController 时,iOS 崩溃

Posted

技术标签:

【中文标题】当系统清除内存并关闭 UIViewController 时,iOS 崩溃【英文标题】:Crash on iOS when system purges memory and closes a UIViewController 【发布时间】:2012-03-19 09:54:43 【问题描述】:

当其中一个视图因内存不足而从内存中清除时,我的应用程序崩溃了。至少这是我从崩溃日志中了解到的。它发生在许多屏幕上,但仅在打开 Facebook 对话框时发生(使用 Facebook SDK)。基本上,当我们需要呈现 Facebook 对话框(例如,让用户在 Facebook 时间轴上发布内容)时,系统有时会出现内存不足的情况。

Date/Time: 2012-03-14 19:47:33.819 +0000
OS Version: iPhone OS 5.1 (9B176)
Report Version: 104
Exception Type: EXC_BAD_ACCESS (SIGSEGV)
Exception Codes: KERN_INVALID_ADDRESS at 0x30000008
Crashed Thread: 0
Thread 0 name: Dispatch queue: com.apple.main-thread
Thread 0 Crashed:
0 libobjc.A.dylib 0x30f2bf78 objc_msgSend + 16
1 MyApp 0x00003c0e -LTBaseViewController viewDidUnload (LTBaseViewController.m:145)
2 MyApp 0x00004ea2 -LTBaseTableViewController viewDidUnload (LTBaseTableViewController.m:90)
3 UIKit 0x33766bd8 -[UIViewController unloadViewForced:] + 244
4 UIKit 0x338ae492 -[UIViewController purgeMemoryForReason:] + 58
5 Foundation 0x3071a4f8 __57-NSNotificationCenter addObserver:selector:name:object:_block_invoke_0 + 12
6 CoreFoundation 0x30e95540 ___CFXNotificationPost_block_invoke_0 + 64
7 CoreFoundation 0x30e21090 _CFXNotificationPost + 1400
8 Foundation 0x3068e3e4 -NSNotificationCenter postNotificationName:object:userInfo: + 60
9 Foundation 0x3068fc14 -NSNotificationCenter postNotificationName:object: + 24
10 UIKit 0x3387926a -UIApplication _performMemoryWarning + 74
11 UIKit 0x33879364 -UIApplication _receivedMemoryNotification + 168
12 libdispatch.dylib 0x36a12252 _dispatch_source_invoke + 510
13 libdispatch.dylib 0x36a0fb1e _dispatch_queue_invoke$VARIANT$up + 42
14 libdispatch.dylib 0x36a0fe64 _dispatch_main_queue_callback_4CF$VARIANT$up + 152
15 CoreFoundation 0x30e9c2a6 __CFRunLoopRun + 1262
16 CoreFoundation 0x30e1f49e CFRunLoopRunSpecific + 294
17 CoreFoundation 0x30e1f366 CFRunLoopRunInMode + 98
18 GraphicsServices 0x33fb6432 GSEventRunModal + 130
19 UIKit 0x336f5e76 UIApplicationMain + 1074
20 MyApp 0x00004818 main (main.m:16)
21 MyApp 0x000023b4 0x1000 + 5044

我检查了一下,几乎没有内存泄漏,例如在测试应用程序一小时时,由于某些字符串复制库导致泄漏的总内存约为 2-3Kb。所以我不相信这是由应用程序引起的。我猜当手机有一段时间没有重新启动时,后台运行着一些应用程序,而当使用 Facebook SDK 时,内存就会出现问题,系统会尝试从随机应用程序(包括我的应用程序)中恢复内存。

我的问题是,我怎样才能防止这种崩溃发生?我应该如何处理视图控制器上的 unloadViewForced 以使应用程序在低内存条件下更加健壮?最后,这个崩溃日志表明发生崩溃是因为系统试图释放内存而我的应用程序没有正确处理它,我说得对吗?

非常感谢任何帮助。

【问题讨论】:

在模拟器中运行并使用“模拟内存警告”菜单项时是否也会出现这种崩溃? 没试过,不知道这个功能。将尝试找出答案。感谢您的提示。 不,它没有 :( 我们不会在应用程序的任何地方处理 didReceiveMemoryWarning。在模拟器的菜单中单击该选项只会在控制台上打印一条消息,除此之外什么都不做。 我刚刚回忆起如何正确使用该功能。您需要确保活动视图控制器不是您遇到崩溃的视图控制器。确保另一个视图控制器处于活动状态,然后使用菜单项。然后将要求非活动视图控制器释放内存。 谢谢,您想到的“菜单项”是什么?很难说到底是哪个控制器发生了崩溃,因为 LTBaseViewController 是我们所有控制器的基类。所以崩溃日志不会告诉哪个控制器确切地崩溃了。我以为它是最上面的,但你说得对,它可能是堆栈中的任何底层控制器。 【参考方案1】:

最有可能发生的是,LTBaseViewController viewDidUnload 方法引用并可能正在释放的对象之一正在被双重释放。事实上,由于回溯表明崩溃发生在 LTBaseViewController.m 的第 145 行,您应该能够快速查看哪个对象是罪魁祸首。

【讨论】:

忘了提到应用程序中的内存是由 ARC 管理的。所以没有手动释放对象。另外,我不相信函数右侧的数字是线。例如。我的代码中的 LTBaseViewController 中没有 viewDidUnload,因此它正在调用父实现。这是从函数开头的字节偏移量。我需要使用交错的代码指令编译到汇编程序,以找出问题发生在哪一行,但我不确定如何在 MAC 上做到这一点。 LTBaseViewController.m 的第 145 行是什么? (不是 LTBaseTableViewController.m)。 方法 viewWillAppear 的结束子句 ''。 看这一行:21 MyApp 0x000023b4 0x1000 + 5044 这当然并不意味着崩溃发生在MyApp源代码的第5044行。但是,它确实表明它发生在距应用程序加载到内存的地址偏移 5044 字节处。 如果您查看堆栈跟踪行的末尾,它会显示LTBaseViewController.m:145。这表明问题出现在“LTBaseViewController.m”的第 145 行。 (但是,如果源代码在生成堆栈跟踪后发生了变化,它们可能会有所不同。)

以上是关于当系统清除内存并关闭 UIViewController 时,iOS 崩溃的主要内容,如果未能解决你的问题,请参考以下文章

Linux服务器中由于内存不足导致tomcat自动关闭解决方案

如何在 ubuntu 上彻底清除并重新安装 postgresql? [关闭]

如何清除内存缓存?

为啥关闭视图控制器不会从内存中清除呈现的控制器?

怎么清除虚拟内存?pagefile.sys

android 怎么做数据缓存