iOS的内存分配(堆栈)
程序员文章站
2024-03-24 13:55:10
...
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为两片不同内存对象。
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指向同一个堆对象。