神刀安全网

iOS开发中的内存分配(堆和栈)

前言

因为前段时间因为一些事情而晚上失眠多梦,身体素质直线下降,前天下班后去健身房减完身,感到恶心难受,后来发生了一个我不敢想象的时候,我竟然吐血了!这可把我吓的啊,立马到医院检查!拿到血液检查报告给医生。

医生:没什么严重的问题,就是有点发炎,
我:我都吐血了,就是有点炎症?
医生:这检查报告数据上显示没什么问题,你要不放心做个CT检查看看,不过今天晚上CT机器坏了!
我:我这种吐血可能因为什么原因导致的?
医生:具体什么原因不好说。

这是一个三甲医院,还是急诊专家,就给我这样的答复!我还是好好修养一段时间(蓝瘦 香菇),我对中国的医疗很失望。。。(楼主失望有卵用?)

iOS开发中的内存分配(堆和栈)
现在心情:蓝瘦,香菇.jpeg

我心里还是很害怕,因为我还没活够呢(贪生怕死)!我还有好多事没有去做呢,我不能英年早逝啊(哪来的英年?)。

通过我这个事情,希望所有的人,一定要爱护好自己的身体,晚上一定不要熬夜!

身体是革命的本钱

看完我的经历,你们可能会感觉楼主这么多P事,其实不是楼主事多,其实每一个人事都特多,只是没有留心观察,人生一直充满这未知。我一直以为现实比小说精彩.

现实比小说精彩

iOS开发中的内存分配(堆和栈)
楼主无时无刻不在装X.jpeg

老生长谈的一个话题,你们也都知道,我就是总结一下给自己看的,你们就看看笑话就行。本文的堆和栈是操作系统的内存中堆和栈,不是数据结构中的堆和栈。

进程的内存分区

所有进程(执行的程序)都必须占用一定数量的内存,它或是用来存放从磁盘载入的程序代码,或是存放取自用户输入的数据等等。不过进程对这些内存的管理方式因内存用途不一而不尽相同,有些内存是事先静态分配和统一回收的,而有些却是按需要动态分配和回收的。

iOS开发中的内存分配(堆和栈)
进程内存区域.png

  1. 代码区:代码段是用来存放可执行文件的操作指令(存放函数的二进制代码),也就是说是它是可执行程序在内存种的镜像。代码段需要防止在运行时被非法修改,所以只准许读取操作,而不允许写入(修改)操作——它是不可写的。

  2. 全局(静态)区包含下面两个分区:

    • 数据区:数据段用来存放可执行文件中已初始化全局变量,换句话说就是存放程序静态分配的变量和全局变量。

    • BSS区:BSS段包含了程序中未初始化全局变量。

  3. 常量区:常量存储区,这是一块比较特殊的存储区,他们里面存放的是常量,

  4. 堆(heap)区:堆是由程序员分配和释放,用于存放进程运行中被动态分配的内存段,它大小并不固定,可动态扩张或缩减。当进程调用alloc等函数分配内存时,新分配的内存就被动态添加到堆上(堆被扩张);当利用realse释放内存时,被释放的内存从堆中被剔除(堆被缩减),因为我们现在iOS基本都使用ARC来管理对象,所以不用我们程序员来管理,但是我们要知道这个对象存储的位置。

  5. 栈(stack)区:栈是由编译器自动分配并释放,用户存放程序临时创建的局部变量,存放函数的参数值,局部变量等。也就是说我们函数括弧“{}”中定义的变量(但不包括static声明的变量,static意味这在数据段中存放变量)。除此以外在函数被调用时,其参数也会被压入发起调用的进程栈中,并且待到调用结束后,函数的返回值也回被存放回栈中。由于栈的先进先出特点,所以栈特别方便用来保存/恢复调用现场。从这个意义上将我们可以把栈看成一个临时数据寄存、交换的内存区。

上述几种内存区域中数据段、BSS和堆通常是被连续存储的——内存位置上是连续的,而代码段和栈往往会被独立存放。

栈是向低地址扩展的数据结构,是一块连续的内存的区域。堆是向高地址扩展的数据结构,是不连续的内存区域。有人会问堆和栈会不会碰到一起,他们之间间隔很大,绝少有机会能碰到一起,况且堆是链表方式存储!

#import "ViewController.h"  int age = 24;//全局初始化区(数据区) NSString *name;//全局未初始化区(BSS区) static NSString *sName = @"Dely";//全局(静态初始化)区  @implementation ViewController  - (void)viewDidLoad {     [super viewDidLoad];      int tmpAge;//栈     NSString *tmpName = @"Dely";//栈     NSString *number = @"123456"; //123456/0在常量区,number在栈上。     NSMutableArray *array = [NSMutableArray arrayWithCapacity:1];//分配而来的8字节的区域就在堆中,array在栈中,指向堆区的地址     NSInteger total = [self getTotalNumber:1 number2:1];  }  - (NSInteger)getTotalNumber:(NSInteger)number1 number2:(NSInteger)number2{     return number1 + number2;//number1和number2 栈区 }   @end

堆(heap)和栈(stack)区别

  1. 申请方式和回收方式

    • 栈区(stack) :由编译器自动分配并释放
    • 堆区(heap):由程序员分配和释放
  2. 申请后系统的响应

    • 栈区(stack):存储每一个函数在执行的时候都会向操作系统索要资源,栈区就是函数运行时的内存,栈区中的变量由编译器负责分配和释放,内存随着函数的运行分配,随着函数的结束而释放,由系统自动完成。只要栈的剩余空间大于所申请空间,系统将为程序提供内存,否则将报异常提示栈溢出。

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

  3. 申请大小的限制

    • 栈区(stack):栈是向低地址扩展的数据结构,是一块连续的内存的区域。这句话的意思是栈顶的地址和栈的最大容量是系统预先规定好的,栈的大小是2M(也可能是1M,我看网上说得,我也不清楚),如果申请的空间超过栈的剩余空间时,将提示栈溢出。因此,能从栈获得的空间较小。

    • 堆区(stack):堆是向高地址扩展的数据结构,是不连续的内存区域。这是由于系统是用链表来存储的空闲内存地址的,自然是不连续的,而链表的遍历方向是由低地址向高地址。堆的大小受限于计算机系统中有效的虚拟内存。由此可见,堆获得的空间比较灵活,也比较大。

  4. 申请效率的比较

    • 栈区(stack):由系统自动分配,速度较快。但程序员是无法控制的。

    • 堆区(stack):是由alloc分配的内存,一般速度比较慢,而且容易产生内存碎片,不过用起来最方便.

  5. 分配方式的比较

    • 栈区(stack):有2种分配方式:静态分配和动态分配。静态分配是编译器完成的,比如局部变量的分配。动态分配由alloc函数进行分配,但是栈的动态分配和堆是不同的,他的动态分配是由编译器进行释放,无需我们手工实现。
    • 堆区(stack):堆都是动态分配的,没有静态分配的堆。
  6. 分配效率的比较

    • 栈区(stack):栈是操作系统提供的数据结构,计算机会在底层对栈提供支持:分配专门的寄存器存放栈的地址,压栈出栈都有专门的指令执行,这就决定了栈的效率比较高。
    • 堆区(stack):堆则是C/C++函数库提供的,它的机制是很复杂的,例如为了分配一块内存,库函数会按照一定的算法(具体的算法可以参考数据结构/操作系统)在堆内存中搜索可用的足够大小的空间,如果没有足够大小的空间(可能是由于内存碎片太多),就有可能调用系统功能去增加程序数据段的内存空间,这样就有机会分到足够大小的内存,然后进行返回。显然,堆的效率比栈要低得多。

小结:
使用栈就像我们去买一个蛋糕,出钱然后选择一种口味,一种形状的蛋糕就得到了,不管他们怎么做的,怎么设计的,这种好处就是快捷,花钱买服务嘛(我是不是说的不好,有点污了),但是自由度很小。。

使用堆就像我们去买一个手工蛋糕,因为有情义啊DIY,自己动手做喜欢吃的形状,和自己喜欢的口味,比较麻烦,但是比较符合自己的口味,而且自由度大。

今天的牛X就吹到这里,中间有什么错误请提出来狠狠批斗我,谢谢你们的赏脸查看!

参考资料:
http://blog.csdn.net/liruxing1715/article/details/6715503

转载本站任何文章请注明:转载至神刀安全网,谢谢神刀安全网 » iOS开发中的内存分配(堆和栈)

分享到:更多 ()

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址