注册

iOS内存(Heap堆内存 && Anonymous VM 虚拟内存) 分析和理解

在使用Instruments 做内存分析的时候, 我们会看到如下的画面,箭头指向的地方有堆内存heap Allocations,和虚拟内存 Anonymous VM , 到底在手机上什么是堆内存,什么是虚拟内存 Anonymous VM 呢? 在观察内存分配的时候 我们是否需要
去了解它

前言所需要的图片(如下图)

8c74d5aa4d2cf51bb24c137a974833fc.png

1) 什么是堆
堆是一种完全结构的二叉树 堆与二叉树的理解

堆: 是大家共有的空间,分全局堆和局部堆。全局堆就是所有没有分配的空间,局部堆就是用户分配的空间。堆在操作系统对进程 初始化的时候分配,运行过程中也可以向系统要额外的堆,但是记得用完了要还给操作系统,要不然就是内存泄漏。堆里面一般 放的是静态数据,比如static的数据和字符串常量等,资源加载后一般也放在堆里面。一个进程的所有线程共有这些堆 ,所以对堆的操作要考虑同步和互斥的问题。程序里面编译后的数据段都是堆的一部分。

— 一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收。注意它与数据结构中的堆是两回事,分配方式倒是类似于链表

{
int b; //栈
char s[] = "abc"; //栈
char *p2; //栈
char *p3 = "123456"; //123456{row.content}在常量区,p3在栈上。
static int c =0; //全局(静态)初始化区
p1 = (char *)malloc(10);
p2 = (char *)malloc(20);//分配得来的10和20字节的区域就在堆区。
strcpy(p1, "123456"); //123456{row.content}放在常量区,编译器可能会将它与p3所指向的"123456"优化成一个地方。}

堆:首 先应该知道操作系统有一个记录空闲内存地址的链表,当系统收到程序的申请时,会遍历该链表,寻找第一个空间大于所申请空间的堆结点,然后将该结点从空闲结 点链表中删除,并将该结点的空间分配给程序,另外,对于大多数系统,会在这块内存空间中的首地址处记录本次分配的大小,这样,代码中的delete语句才 能正确的释放本内存空间。另外,由于找到的堆结点的大小不一定正好等于申请的大小,系统会自动的将多余的那部分重新放入空闲链表中。

堆是向高地址扩展的数据结构,是不连续的内存区域。这是由于系统是用链表来存储的空闲内存地址的,自然是不连续的,而链表的遍历方向是由低地址向高地址。堆的大小受限于计算机系统中有效的虚拟内存。由此可见,堆获得的空间比较灵活,也比较大。碎片问题:对于堆来讲,频繁的new/delete势必会造成内存空间的不连续,从而造成大量的碎片,使程序效率降低。对于栈来讲,则不会存在这个问题,因为栈是先进后出的队列,他们是如此的一一对应,以至于永远都不可能有一个内存块从栈中间弹出分配方式:堆都是动态分配的,没有静态分配的堆。

1.1) 堆上消耗的内存

04a2972e5749637efc9e1aef4c7046be.png

1、View 函数的调用
2、注册通知
3、抛出通知
4、view 的布局
5、函数代码的执行
6、sqlite 数据库的创建
7、向字典中增加对象

53296df8225a74d76cfaedf35c410d81.png

8、等等

都需要消耗内存, 上面的代码都是程序员创建的, 程序员去控制堆的内存

1.2) 堆上的内存是否释放

1.2.1) 已经释放的例子:

点击步骤1)箭头

15014a876bca466eef32321b63167a55.png

查看步骤2)箭头

77a112c5cf16733063c202f1644d1840.png

步骤2) 箭头中有 free 函数, 可以看出, 这个对象 已经被释放

1.2.2) 堆上内存不释放的例子:

ff648e9f8f63d8362257f1f5f62254ee.png

上图中箭头执行的地方 没有free 函数 说明 这个对象已经释放

2) Anonymous VM

2.1) 苹果官方文档对虚拟内存的解释

更小的内存消耗不仅可以减少内存, 还可以减少cpu 的时间
我们可能会看到这样的情况, All Heap Allocations 是程序真实的内存分配情况,All Anonymous VM则是系统为程序分配的虚拟内存,为的就是当程序有需要的时候,能够及时为程序提供足够的内存空间,而不会现用现创建

Anonymous VM内存是虚拟内存
、All Anonymous VM。我们无法控制Anonymous VM部分 ,(更新,其实还是可以优化 比如图片绘制相关 详情参见iOS内存探究,需要对虚拟内存熟悉 才能优化)

2.2) 问题: 我们需要关注Anonymous VM 内存吗 ?
问答连接
Should you focus on the Live Bytes column for heap allocations or anonymous VM? Focus on the heap allocations because your app has more control over heap allocations. Most of the memory allocations your app makes are heap allocations.

The VM in anonymous VM stands for virtual memory. When your app launches, the operating system reserves a block of virtual memory for your application. This block is usually much larger than the amount of memory your app needs. When your app allocates memory, the operating system allocates the memory from the block it reserved.

Remember the second sentence in the previous paragraph. The operating system determines the size of the virtual memory block, not your app. That’s why you should focus on the heap allocations instead of anonymous VM. Your app has no control over the size of the anonymous VM.

2.3) 不需要关注 Anonymous VM
我们应该关注堆内存, 因为我们对堆内存有更大的掌控, 大部分我们在app的内存分配是堆内存

VM 在匿名空间中代表的是虚拟内存, 当你的app启动的时候, 操作系统为你的应用程序分配内存, 这个分配的虚拟内存一般比你的app需要的内存大很多,

操作系统决定虚拟内存的分配, 而不是你的app, 这就是你为什么要集中精力处理堆内存, 你的app 对虚拟内存没有掌控力

2.4) 虚拟内存过大 (未解之谜) 如果知道结果请评论留言, 多谢

bd091e8e4cde3a121205a4ccd2ea3292.png

CGBitmapContextCreateImage 函数会导致虚拟内存过大 ,并且还不释放, 用法未发现问题

CGImageRef alphaMaskImage = CGBitmapContextCreateImage(alphaOnlyContext);
UIImage *result = [UIImage imageWithCGImage:alphaMaskImage scale:image.scale orientation:image.imageOrientation];
CGImageRelease(alphaMaskImage);
CGContextRelease(alphaOnlyContext);
return result;

参考文献

iOS中的堆(heap)和栈(stack)的理解

苹果虚拟内存的官方文档

转自:https://www.jianshu.com/p/dffd5c24dc9a

0 个评论

要回复文章请先登录注册