iOS进阶iOS 实用技术上海恩美路演

让人懵逼的 iOS 系统内存分配问题

2017-03-09  本文已影响4336人  Joy___

最近应用中出现低内存被杀的情况,所以就想办法对造成这一个问题的根源进行定位,主要是两个比较 Low 的思路

让人懵逼的地方就是如何获取 app 的内存和设备的整体内存情况,在网上查了一下,答案千奇百怪,而且统计的结果差异也比较大,所以才有了此文

系统内存分配

据查阅 Apple 的官方文档,操作系统的内存主要分为 Used MemoryFree MemoryUsed Memory 又可以分为Wired MemoryActive MemoryInactive Memory,同时提到了一个Purgeable Memory ,暂且把它归类为 Active Memory 吧。

应用物理内存

这个就是理解上的物理内存,对于 app 的内存使用应该检测这一数值的变化,而检测虚拟内存的话意义不大,对于物理内存和虚拟内存在 iOS 上的分配可以查看这篇文章:先弄清楚这里的学问,再来谈 iOS 内存管理与优化(一)。对于物理内存的用量检测方法比较常见:(更新正确的获取App内存占用的方法:http://ddrccw.github.io/2017/12/30/reverse-xcode-with-lldb-and-hopper-disassemblerhttp://www.samirchen.com/ios-app-memory-usage/

// 获得当前 App 的内存占用情况
- (NSUInteger)getResidentMemory {
    struct task_basic_info t_info;
    mach_msg_type_number_t t_info_count = TASK_BASIC_INFO_COUNT;
    
    int r = task_info(mach_task_self(), TASK_BASIC_INFO, (task_info_t)&t_info, &t_info_count);
    if (r == KERN_SUCCESS) {
        
        NSLog(@"resident_size %lu",t_info.resident_size / 1024/1024);
        
        return t_info.resident_size;
    }
    else {
        return -1;
    }
}

测试

我主要是在 app 中放了一个按钮,每点击一次分配一百兆物理内存,然后查看 app 的内存使用情况以及系统的内存分配情况,对于系统的内存分配查看方式,可以参考这里:iOS-System-Services/System Services/Utilities/SSMemoryInfo.m

在 app 低内存崩溃前,一直收集点击按钮后的内存变化,如下

2017-03-09 21:28:03.112138 LDAPM[491:46357] TotalMemory 2048.000000
2017-03-09 21:28:03.112280 LDAPM[491:46357] free 549.734375
2017-03-09 21:28:03.112338 LDAPM[491:46357] TotalMemory 2048.000000
2017-03-09 21:28:03.112361 LDAPM[491:46357] used 1226.390625
2017-03-09 21:28:03.112381 LDAPM[491:46357] active 740.156250
2017-03-09 21:28:03.112399 LDAPM[491:46357] inactive 291.109375
2017-03-09 21:28:03.112417 LDAPM[491:46357] wired 195.125000
2017-03-09 21:28:03.112544 LDAPM[491:46357] purgableMemory 11.515625
2017-03-09 21:28:03.112613 LDAPM[491:46357] resident_size 27

2017-03-09 21:28:36.326194 LDAPM[491:46357] TotalMemory 2048.000000
2017-03-09 21:28:36.326284 LDAPM[491:46357] free 448.093750
2017-03-09 21:28:36.326307 LDAPM[491:46357] TotalMemory 2048.000000
2017-03-09 21:28:36.326322 LDAPM[491:46357] used 1330.734375
2017-03-09 21:28:36.326340 LDAPM[491:46357] active 846.015625
2017-03-09 21:28:36.326358 LDAPM[491:46357] inactive 289.593750
2017-03-09 21:28:36.326377 LDAPM[491:46357] wired 195.125000
2017-03-09 21:28:36.326395 LDAPM[491:46357] purgableMemory 12.531250
2017-03-09 21:28:36.326450 LDAPM[491:46357] resident_size 134

2017-03-09 21:28:42.708484 LDAPM[491:46357] TotalMemory 2048.000000
2017-03-09 21:28:42.708571 LDAPM[491:46357] free 352.718750
2017-03-09 21:28:42.708593 LDAPM[491:46357] TotalMemory 2048.000000
2017-03-09 21:28:42.708607 LDAPM[491:46357] used 1427.968750
2017-03-09 21:28:42.708626 LDAPM[491:46357] active 944.703125
2017-03-09 21:28:42.708656 LDAPM[491:46357] inactive 289.203125
2017-03-09 21:28:42.708677 LDAPM[491:46357] wired 194.062500
2017-03-09 21:28:42.708695 LDAPM[491:46357] purgableMemory 12.531250
2017-03-09 21:28:42.708715 LDAPM[491:46357] resident_size 234

2017-03-09 21:28:46.940049 LDAPM[491:46357] TotalMemory 2048.000000
2017-03-09 21:28:46.940146 LDAPM[491:46357] free 252.437500
2017-03-09 21:28:46.940166 LDAPM[491:46357] TotalMemory 2048.000000
2017-03-09 21:28:46.940185 LDAPM[491:46357] used 1527.406250
2017-03-09 21:28:46.940203 LDAPM[491:46357] active 1043.875000
2017-03-09 21:28:46.940221 LDAPM[491:46357] inactive 289.484375
2017-03-09 21:28:46.940239 LDAPM[491:46357] wired 194.046875
2017-03-09 21:28:46.940256 LDAPM[491:46357] purgableMemory 12.531250
2017-03-09 21:28:46.940275 LDAPM[491:46357] resident_size 334

2017-03-09 21:28:49.930067 LDAPM[491:46357] TotalMemory 2048.000000
2017-03-09 21:28:49.930154 LDAPM[491:46357] free 152.187500
2017-03-09 21:28:49.930177 LDAPM[491:46357] TotalMemory 2048.000000
2017-03-09 21:28:49.930221 LDAPM[491:46357] used 1627.515625
2017-03-09 21:28:49.930248 LDAPM[491:46357] active 1143.921875
2017-03-09 21:28:49.930267 LDAPM[491:46357] inactive 289.515625
2017-03-09 21:28:49.930285 LDAPM[491:46357] wired 194.078125
2017-03-09 21:28:49.930303 LDAPM[491:46357] purgableMemory 12.593750
2017-03-09 21:28:49.930322 LDAPM[491:46357] resident_size 434

2017-03-09 21:28:52.780752 LDAPM[491:46357] TotalMemory 2048.000000
2017-03-09 21:28:52.780830 LDAPM[491:46357] free 82.390625
2017-03-09 21:28:52.780852 LDAPM[491:46357] TotalMemory 2048.000000
2017-03-09 21:28:52.780867 LDAPM[491:46357] used 1748.640625
2017-03-09 21:28:52.780918 LDAPM[491:46357] active 1078.281250
2017-03-09 21:28:52.780943 LDAPM[491:46357] inactive 479.546875
2017-03-09 21:28:52.780961 LDAPM[491:46357] wired 190.812500
2017-03-09 21:28:52.780979 LDAPM[491:46357] purgableMemory 12.562500
2017-03-09 21:28:52.780999 LDAPM[491:46357] resident_size 534

2017-03-09 21:28:55.454389 LDAPM[491:46357] TotalMemory 2048.000000
2017-03-09 21:28:55.454456 LDAPM[491:46357] free 21.062500
2017-03-09 21:28:55.454476 LDAPM[491:46357] TotalMemory 2048.000000
2017-03-09 21:28:55.454493 LDAPM[491:46357] used 1801.875000
2017-03-09 21:28:55.454511 LDAPM[491:46357] active 1070.968750
2017-03-09 21:28:55.454529 LDAPM[491:46357] inactive 540.312500
2017-03-09 21:28:55.454546 LDAPM[491:46357] wired 190.593750
2017-03-09 21:28:55.454564 LDAPM[491:46357] purgableMemory 10.906250
2017-03-09 21:28:55.454587 LDAPM[491:46357] resident_size 634

2017-03-09 21:28:58.757493 LDAPM[491:46357] TotalMemory 2048.000000
2017-03-09 21:28:58.757688 LDAPM[491:46357] free 25.484375
2017-03-09 21:28:58.757710 LDAPM[491:46357] TotalMemory 2048.000000
2017-03-09 21:28:58.757804 LDAPM[491:46357] used 1119.265625
2017-03-09 21:28:58.757830 LDAPM[491:46357] active 624.609375
2017-03-09 21:28:58.757848 LDAPM[491:46357] inactive 303.906250
2017-03-09 21:28:58.757866 LDAPM[491:46357] wired 190.796875
2017-03-09 21:28:58.757889 LDAPM[491:46357] resident_size 59

2017-03-09 21:29:00.488180 LDAPM[491:46357] TotalMemory 2048.000000
2017-03-09 21:29:00.488253 LDAPM[491:46357] free 38.281250
2017-03-09 21:29:00.488273 LDAPM[491:46357] TotalMemory 2048.000000
2017-03-09 21:29:00.488289 LDAPM[491:46357] used 1020.781250
2017-03-09 21:29:00.488308 LDAPM[491:46357] active 563.328125
2017-03-09 21:29:00.488326 LDAPM[491:46357] inactive 267.046875
2017-03-09 21:29:00.488343 LDAPM[491:46357] wired 190.406250
2017-03-09 21:29:00.488382 LDAPM[491:46357] purgableMemory 0.062500
2017-03-09 21:29:00.488416 LDAPM[491:46357] resident_size 126

2017-03-09 21:29:02.915796 LDAPM[491:46357] TotalMemory 2048.000000
2017-03-09 21:29:02.915882 LDAPM[491:46357] free 46.578125
2017-03-09 21:29:02.915902 LDAPM[491:46357] TotalMemory 2048.000000
2017-03-09 21:29:02.915917 LDAPM[491:46357] used 844.250000
2017-03-09 21:29:02.915935 LDAPM[491:46357] active 448.140625
2017-03-09 21:29:02.915952 LDAPM[491:46357] inactive 204.609375
2017-03-09 21:29:02.915970 LDAPM[491:46357] wired 191.500000
2017-03-09 21:29:02.915993 LDAPM[491:46357] resident_size 63

2017-03-09 21:29:05.359697 LDAPM[491:46357] TotalMemory 2048.000000
2017-03-09 21:29:05.359786 LDAPM[491:46357] free 39.750000
2017-03-09 21:29:05.359810 LDAPM[491:46357] TotalMemory 2048.000000
2017-03-09 21:29:05.359858 LDAPM[491:46357] used 730.562500
2017-03-09 21:29:05.359885 LDAPM[491:46357] active 363.437500
2017-03-09 21:29:05.359904 LDAPM[491:46357] inactive 176.109375
2017-03-09 21:29:05.359922 LDAPM[491:46357] wired 191.015625
2017-03-09 21:29:05.359979 LDAPM[491:46357] resident_size 53

2017-03-09 21:29:08.239699 LDAPM[491:46357] TotalMemory 2048.000000
2017-03-09 21:29:08.239776 LDAPM[491:46357] free 36.656250
2017-03-09 21:29:08.239797 LDAPM[491:46357] TotalMemory 2048.000000
2017-03-09 21:29:08.239813 LDAPM[491:46357] used 621.703125
2017-03-09 21:29:08.239831 LDAPM[491:46357] active 288.640625
2017-03-09 21:29:08.239848 LDAPM[491:46357] inactive 142.781250
2017-03-09 21:29:08.239865 LDAPM[491:46357] wired 190.281250
2017-03-09 21:29:08.240040 LDAPM[491:46357] resident_size 39

2017-03-09 21:29:11.167796 LDAPM[491:46357] TotalMemory 2048.000000
2017-03-09 21:29:11.167871 LDAPM[491:46357] free 34.109375
2017-03-09 21:29:11.167893 LDAPM[491:46357] TotalMemory 2048.000000
2017-03-09 21:29:11.168042 LDAPM[491:46357] used 638.437500
2017-03-09 21:29:11.168088 LDAPM[491:46357] active 311.562500
2017-03-09 21:29:11.168244 LDAPM[491:46357] inactive 149.296875
2017-03-09 21:29:11.168373 LDAPM[491:46357] wired 177.625000
2017-03-09 21:29:11.168492 LDAPM[491:46357] resident_size 85

2017-03-09 21:29:13.845295 LDAPM[491:46357] TotalMemory 2048.000000
2017-03-09 21:29:13.845364 LDAPM[491:46357] free 41.937500
2017-03-09 21:29:13.845385 LDAPM[491:46357] TotalMemory 2048.000000
2017-03-09 21:29:13.845401 LDAPM[491:46357] used 637.250000
2017-03-09 21:29:13.845419 LDAPM[491:46357] active 321.453125
2017-03-09 21:29:13.845440 LDAPM[491:46357] inactive 145.171875
2017-03-09 21:29:13.845458 LDAPM[491:46357] wired 170.640625
2017-03-09 21:29:13.845522 LDAPM[491:46357] resident_size 152

2017-03-09 21:29:13.855866 LDAPM[491:46357] applicationDidReceiveMemoryWarning
Message from debugger: Terminated due to memory issue

可以发现在我们的 app 内存使用正常的情况下,free 内存、 active 内存以及 app 当前的物理内存变化都是很正常的,以 100 为单位变化。但是后期 app 要求分配过多内存的时候,发现 active 内存不再以 100 为额度增长,这个时候应该是操作系统基于 jetsam 机制开始杀死一些后台优先级低的 app 了。再进一步看,发现内存紧张的时候,purgeableMemory 不再打印了,是因为它的值变为了 0,所以我没有继续打印,也符合刚才的描述,在内存紧张时,可以自动释放的内存,这一手段也可以用来降低内存峰值。

Q & A

1.为什么 app 崩溃的时候,我的应用使用内存不多,但是系统剩余内存很少的情况下,首先杀掉了我的应用呢?

这个问题,我以前也比较好奇,觉得这个不符合常理。但是通过刚才的测试来看,在自身物理内存不断申请的情况下,当物理内存过大的时候,通过以上代码收集到的值并不是很大,反而变小了。可能是代码的问题,也可能是操作系统的问题。但是你所使用的代码或者第三方平台的收集策略很可能与此类似。收集到一个很小的值,但是并不代表你的 app 的内存使用情况很正确,很可能存在内存暴涨,但是收集结果却没有显示出来。

2. 为什么上面的数据 free memory + used memory (active + inactive + purgeableMemory) 的值不等于 TotalMemory 呢?

这个问题我也很好奇,而且会发现当你自身 app 内存申请不合理的时候 free memory + used memory 的值也会和正常情况下不同,目前只能猜测系统用这块内存来做了什么神秘的事情,如有对操作系统熟悉的同学,望告知!!

上一篇下一篇

猜你喜欢

热点阅读