欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

iOS的内存分配(堆栈)

程序员文章站 2024-03-24 13:55:10
...

iOS中堆栈

iOS内存模块

一个应用的内存主要分为堆、栈、全局区/静态区、常量区、代码区

如下图:

iOS的内存分配(堆栈)

栈(stack)

由编译器管理自动释放,如方法内变量,局部变量等值。分配时只要栈的空间大于对象申请的空间,就会提供该段内存,否则报栈溢出。

对于一个方法,在方法作用域内形成一个栈帧(stack frame)(包含参数,局部变量,返回值等),执行完方法后,栈帧弹出,里面所有内存销毁。

特点:

  • 存放局部变量,函数跳转地址,指针地址,值类型对象等,先进先出,出了作用域就销毁。
  • 开发者不需要管理栈区内存,分配由高到低。
  • 内存分配是连续的。

优点

  • 速度快,管理简单,有严格生命周期
  • 一般不会出现内存泄露问题(还是有小机率造成循环引用的内存泄露)

缺点

  • 不灵活,创建时候是多大以后就多大,且owner只有一个。

堆(heap)

由开发者分配释放(或者编译器自动添加释放命令),不释放可能引起内存泄露。分配时,堆内采用链表形式管理内存段,需要分配时对链表进行遍历,找到空间大于申请的节点分配给开发者,然后在链表中删除节点。

特点:

  • 堆区分配使用alloc, Swift的引用类型内存在堆区
  • 开发者自行管理,ARC由编译器自动添加管理命令
  • 地址由低到高,内存分配靠遍历链表查找

优点

  • 可以使用引用计数让多个ower拥有(只有heap内对象才可以用"引用计数")

全局区/静态区(static)

主要为全局变量和静态变量分配内存,分为、初始值和未初始过的两个部分。

相关问题

block使用copy属性关键字的原因

block定义后存在栈区,如果作用域改变,就会导致block可能被回收,所以当赋值操作时,进行copy操作,将block拷贝到堆区,保证使用过程不会被回收。

weak对象释放时自动置为nil实现

系统有一个weakhash表,将weak标记的对象地址注册到表中,如果对象被destory销毁,则在weak表中将改对象地址置为nil。

苹果内存引用实现

通过引用计数hash表来实现,对hash表进行操作来实现。引用计数表记录内存地址,以便找到对象。

Swift值类型与引用类型内存分配区别

值类型直接在栈区分配对象的内存,引用类型(class)先在堆分配对象内存,然后再在栈区分配对象的指针。

stack

struct Point {
 var x, y:Double
 func draw() {}
}
let point1 = Point(x:0, y:0) //进行point1初始化,开辟栈内存
var point2 = point1 //初始化point2,拷贝point1内容,开辟新内存
point2.x = 5 //对point2的操作不会影响point1
// use `point1`
// use `point2`

point1和point2为两片不同内存对象。

iOS的内存分配(堆栈)

heap

// Class
class Point {
 var x, y:Double
 func draw() {}
}
let point1 = Point(x:0, y:0) //在堆区分配内存,栈区只是存储地址指针
let point2 = point1 //不产生新的实例,而是对point2增加对堆区内存引用的指针
point2.x = 5 //因为point1和point2是一个实例,所以point1的值也会被修改
// use `point1`
// use `point2`

point1与point2指向同一个堆对象。

iOS的内存分配(堆栈)

参考

iOS开发堆栈你理解多少

深入剖析Swift性能优化