【问题标题】:How to avoid heap fragmentation in iOS如何避免 iOS 中的堆碎片
【发布时间】:2013-12-14 20:09:36
【问题描述】:

我们的应用在运行时会创建很多小对象。它主要归结为自动释放的 NSString 和 NSNumber 对象。由于该应用程序旨在“24/7”在后台运行,因此堆碎片成为一个大问题。

如果不完全重组程序,有哪些技术可以避免这种情况。

我在想: - 对象池,在最终发布后将对象返回到池中,但对象需要是可变的。 (NSMuttableString 会自己造成堆碎片吗?)

其他人如何处理这个问题?

编辑:这就是我怀疑内存碎片的原因。看rpages和[vm-pageshortage]

    eIncident Identifier: 81E87769-8E16-4439-AFFA-6D077E01E5ED
CrashReporter Key:   96235931c31c6b92a16f5c1b1e4cb363a3d18a67
Hardware Model:      iPhone4,1
OS Version:          iPhone OS 7.0.4 (11B554a)
Kernel Version:      Darwin Kernel Version 14.0.0: Fri Sep 27 23:00:48 PDT 2013; root:xnu-2423.3.12~1/RELEASE_ARM_S5L8940X
Date:                2013-12-13 22:43:36 -0800
Time since snapshot: 1582 ms

Free pages:                              1105
Active pages:                            3668
Inactive pages:                          2035
Speculative pages:                       46
Throttled pages:                         100120
Purgeable pages:                         0
Wired pages:                             22159
File-backed pages:                       5400
Anonymous pages:                         349
Compressions:                            0
Decompressions:                          0
Compressor Size:                         0
Uncompressed Pages in Compressor:        0
Largest process:   Argus

Processes
     Name                    <UUID>                       rpages       recent_max   fds      [reason]          (state)

        Facebook <979b9707d85a31df94b986d91d8c3ce7>         2368             2368  100   [vm-pageshortage]  (resume)
       MobileSMS <339505ebbbc4301e87379b095a38ba13>         1448             1448  100   [vm-pageshortage]  (background)
      MobileMail <b3574f4bded1315cb2e50e5de205be48>         1575             1575  100   [vm-pageshortage]  (resume) (continuous)
            tccd <1fea8c5a71943151b5cd304c7eb0fd8c>          198              198  100   [vm-pageshortage]  (daemon)
             kbd <be2d64e41bf43e48a09a23fb129eb0b4>          739              739  100   [vm-pageshortage]  (daemon)
      librariand <15fb21b24e823e158caed9f9e9d8b87a>          299              299  100   [vm-pageshortage]  (daemon)
     MobilePhone <10e2242652423ae28f278a807a0d6384>         1852             1852  200   [vm-pageshortage]  (continuous)
       CVMServer <f26614f7fef63e2faa518272f0fc600a>           96               96  200   [vm-pageshortage]  (daemon)
           Argus <d214b453a3453121a8495d5c8eba80fd>        51299            51299  100   [vm-pageshortage]  (location) (frontmost) (resume)
identityservices <18cc20db2e4739a782cc8e38e03eff52>          398              398  100                      (daemon)
           wifid <a5cf99e5a0f032a69bc2f65050b44291>          652              652   25                      (daemon)
         syslogd <6539f4cf4dcf34daadf1d99991926680>          140              140   50                      (daemon)
          powerd <0a253ac2a99236809422214be1700bc0>          126              126  100                      (daemon)
             vmd <93cffd22b64631afa08a42f6a85e1f33>          297              297  100                      (daemon)
         imagent <bef102e1faef39209926fb25f428a71e>          438              438  100                      (daemon)

【问题讨论】:

  • 我只是好奇:您是如何检测/测量堆碎片的?它究竟造成了什么问题?
  • 您打算如何控制这些类的内部内存分配?
  • iOS 在内存不足时会杀死应用程序和其他应用程序。我们确实会处理内存不足警告并将大部分内存清除到 10Mb 左右,所以这不是问题。
  • 在 iOS7 中,未知进程的崩溃日志开始出现,其中列出了因 [vm-pageshortage] 而被杀死的应用程序列表
  • 我认为这是 iOS7 的一个已知缺陷。许多“24/7”应用程序似乎受到了影响。 Safari 经常会导致此崩溃。我们的应用程序也是如此,主要是在 5S 上。你可以做的不多,因为(至少在我们的例子中)我们完全在内存使用的限制范围内。通常在 1GB 设备上使用 200MB。

标签: ios objective-c heap-fragmentation objectpool


【解决方案1】:

解决此问题的一种方法是找到导致碎片问题的“90%”罪魁祸首。您的代码中可能存在导致瑞士奶酪效应的病态状况。

初步行动

不用说您应该首先说服自己,您的高页面使用率是由于碎片化,而不是 由于内存泄漏。 :-)

如果您还没有这样做,使用 Xcode 中的“Instruments”应用程序是在 iOS 模拟器中观察程序分配内存的绝佳方式。使用 AllocationsLeaks 工具可以记录每个对象分配和代码执行的 malloc() 以及方便的时间戳。 (如果 ARC 没有像应有的那样释放内存,Leaks 工具会免费显示对象映射中的循环。)

通常,这些工具会跟踪仍在使用的内存。您可以在 Allocations 配置窗格中选择 Created & Destroyed 选项来跟踪所有内容,可以在摘要信息上方的弹出窗口中查看。

还有一个 VM 页面分配工具可以帮助您解决问题。

可能的补救措施

一旦你确定了罪魁祸首,你就可以重组你的代码来防止这种病态的情况。或者,如果重组成本太高,您可以通过重用内存来减轻条件的影响。

通常,当分析显示对象分配和释放导致漏洞或特定对象以惊人的频率被分配/释放时,我会找出违规的罪魁祸首并将其放入对象“池”中。

这可以像在 NSMutableArray 中存储对象并根据需要推送和弹出它们一样简单。

当然,您可能想要一些更复杂的东西,即在获取对象时初始化对象,用准备好的对象填充池,并在对象为空或不足时自动重新填充对象。在 iOS 中,如果收集的对象过多或收到内存不足警告,您还需要修剪池。

好消息是,这可以是非常可以永远重复使用的通用代码。 :-)

旁注

你提到了不想让对象可变的问题。在某些情况下(如 NSString),如果您(提前)知道您需要对字符串执行的空间要求和操作,它可以帮助提高效率。这样你就可以提前告诉它你需要多少空间,并对字符串“就地”进行操作,从而减少分配开销。 (NSString 在幕后所做的是另一篇文章。:-)

【讨论】:

    猜你喜欢
    • 2010-09-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-06-22
    • 2013-03-28
    • 2023-03-13
    • 1970-01-01
    • 2014-07-14
    相关资源
    最近更新 更多