iOS 或 MonoTouch 中的固有内存泄漏?
Posted
技术标签:
【中文标题】iOS 或 MonoTouch 中的固有内存泄漏?【英文标题】:Inherent memory leaks in iOS or MonoTouch? 【发布时间】:2013-01-05 12:45:29 【问题描述】:我们正在与 iPad 应用程序中的内存泄漏作斗争,该应用程序必须足够稳定才能保持 24/7 全天候运行,因此,内存泄漏是无法容忍的。
作为一个简单的测试,我们使用“Single View”模板创建了一个新的 iPad MonoTouch 项目,并使用 iPad 本身上的 Instruments 执行它(iPad 3rd gen,没有其他应用程序在运行/在内存中)。
在 Instruments 中,如果我们经常点击“Mark Memory”按钮,它就会不断消耗内存。不多,但时不时会一点点:
该应用程序实际上并没有对我们做任何事情,但显然正在执行一些分配内存的事情。
这是 ios 问题、MonoTouch 问题还是其他问题?
创建 24/7 全天候 iPad 应用程序的计划是否现实?我们担心当我们开始添加代码时,内存泄漏量也会增加。显然,由于上图中的泄漏,该应用程序可以运行相当长一段时间,但如果它加速运行,内存已满的截止日期将会更快。
【问题讨论】:
框架充满了微小的漏洞。 @Carl:有任何关于此的参考,还是只是一个 WAG? @ctacke 没有参考我通过分析注意到的内容。 【参考方案1】:屏幕截图显示分配 - 不是内存泄漏。您可以要求 Instruments 跟踪泄漏,即没有找到对分配内存的引用。
但是,如果没有更多数据,就不可能说这些是否正常。我们至少需要知道分配来自哪里? Instruments 可以告诉您有关每个分配的更多详细信息。尝试向下钻取每个 heapshot 下的树以查看分配的来源。
由于缓存,经常会出现类似的情况 - 并且在每个级别都完成了。在应用程序代码之外,您会注意到 iOS 和它的框架进行缓存(例如图像、webkit ...)。
Mono 本身会进行缓存,并且还会使用会在需要时增长的内存池。将显示分配(即使已释放),但它不是泄漏 - 释放后,如果可能(例如大小),内存将被重用。
当然,它也可能是一个错误(在应用程序、任何框架、单点触控、iOS 中)。给定时间,如果应用程序发生在错误的位置(例如运行循环的一部分、处理通知......),那么一个小的泄漏就足以使应用程序崩溃。只有找到分配的来源以及它们是否是重复分配(来自同一来源)才能告诉您这些分配的重要性。
编辑(更多)
所以我昨晚用自己的应用程序做了一个实验。下面的屏幕截图显示了 13 小时 45 分钟内的堆增长。
在前 4 小时 (1-13) 中,应用程序处于前台。最后一部分 (14) 应用程序在后台(晚上屏幕关闭)。记录在 #14 之后也停止了,因此该数字没有机会随着时间的推移而下降。
我的应用程序更大(初始基线为 5MB),启动后我没有使用它。一旦我知道初始化完成(它正在加载一个quite large,80MB 数据库),我的第一个“标记堆”就完成了。 OTOH 还 listen to network events,使用 NSNetServiceBrowser
,回调到托管代码(没有任何视觉线索)。
Expanding Heapshot #1 显示单个对象,48 字节,堆栈跟踪以 _ZL13_cache_mallocm
、cache_fill
、lookupMethod
、_class_lookupMethodAndLoadCache3
... .
Expanding Heapshot #2 显示了四个对象,前两个对象的堆栈跟踪中有 CA::Render::Encoder::ObjectCacche::invalidate(...)
和 CGNotificationCenterPostNotification
。第三个是_cache_addForwardEntry
,第四个看起来像Heapshot #1,但和第三个一样,它来自_XReceivedStatusBarDataAndAction
(不是我的应用程序或monotouch直接完成的)。
Expanding Heapshot #3 显示 10 个对象...列出它们有点长,但是它们都在同一个 _XReceivedStatusBarDataAndAction
调用下。
扩展堆 #4 时的模式相同。
Heapshot #5 有一个区别(共 11 个),其中分配来自调度队列 (_xpc_connection_init),但没有可见的托管 (app) 或 mono[touch] 堆栈帧。
扩展堆 #6、#7、#8 时的模式(与 #3 相同)。
Heapshot #9 为空(未分配)。
Heapshot #10、#11 和 #3 一样。
Heapshot #12 也是空的。
Heapshot #13 与 #3 非常相似,但它也缓存相同的图像,CA::Render::Image::caches_encoding()
和另一个 _cache_fill
+lookUpMethod
在收到 _significantTimeChange
通知时发生(未托管或 MT 堆栈帧低于 UIApplicationMain
)。其他一些分配与通知有关。
Heapshot #14 主要是关于通知(可能被告知它将进入后台)。还有一些_cache_fill
分配。
这是 iOS 问题、MonoTouch 问题还是其他问题?
上面没有任何东西指向 MonoTouch 甚至我的应用程序。 OTOH 我没有将其与 ObjC 应用程序进行比较(可能没有时间这样做),但我相信您会看到一些非常接近的东西 - 取决于所使用的 API/服务(并且执行相同操作的应用程序应该显示相同)分配)。
就像我在 YMMV 之前所说的那样,泄漏(或意外的内存保留)通常是特定于 API 的。如果您在仪器会话中发现奇怪的堆栈跟踪,请填写关于它们的错误报告(发送给 Xamarin 或 Apple,取决于堆栈跟踪),以便分析和修复它们(如果有错误)。
创建 24/7 全天候 iPad 应用的计划是否现实?
至于 24/7 运行应用程序,我认为它可以完成 - 但它需要用户的合作(这可能是不现实的)。切换到另一个应用程序(主页按钮、手势)意味着您的应用程序不会在前台,Apple 可以终止任何后台应用程序以回收内存。例如。 App X 内存不足,iOS 开始询问,然后杀死后台应用程序以满足前台应用程序。
【讨论】:
从 iOS 6 开始,“引导式访问”(apple.com/ios/whats-new/#accessibility) 允许禁用硬件按钮,这使得 iPad 对于终端/信息亭更加有趣。因此,24/7 全天候运行 iOS 应用程序不再那么不可能了。 :)以上是关于iOS 或 MonoTouch 中的固有内存泄漏?的主要内容,如果未能解决你的问题,请参考以下文章