参考文献
iOS--------对堆、栈 存储空间的理解
局部变量、 全局变量、 堆、 堆栈、 静态和全局
iOS之NSString的内存
- Objective-C的对象在内存中是以堆的方式分配空间的 并且堆空间是由你释
放的 即release
- 栈由编译器管理自动释放的 在方法中(函数体)定义的变量通常在栈内
"因此如果你的变量要跨函数的话,就需要将其定义为成员变量"
运行代码使用的在三个不同的内存区域
1.text segment 是应用程序运行时应用程序代码存在的内存段 每
一个指令 每一个单个函数 过程 方法和执行代码都存在这个内存段中直到应
用程序退出
2.stack segment(栈区) 先进后出结构
3.heap segment(堆区) 提供一个保存中介贯穿函数的执行过程 全局和静态
变量保存在heap中 直到应用退出
为了访问你创建在heap中的数据 你最少要求有一个保存在stack中的指针 因为你的CPU通过stack中的指针访问heap中的数据
操作系统使用stack段中的指针访问heap段中的对象 如果stack对象的指针没有了 则heap中的对象就不能访问了 这就是内存泄漏的原因
栈区
栈区 由编译器自动分配释放 存放函数的参数值 局部变量等值 其操作方式类
似于数据结构中的栈
stack 对象
stack 对象的优点
1 创建速度快
2 简单管理 有严格的生命周期
stack 对象的缺点
- 不灵活 创建时长度是多长就一直是多大 创建时哪个函数创建的 它的owner
就一直是它 不像heap对象那样有多个owner 其实多个owner 等同于引用计
数 只有heap对象才是采用"引用计数"方法管理它
stack 对象的创建
只要栈的剩余空间大于stack 对象申请创建的空间 操作系统就会为程序提供
这段内存空间 否则将报异常提示栈溢出
堆区
堆区 一般由程序员分配释放 若程序员不释放 则可能会引起内存泄漏 注堆和
数据结构中的堆栈不一样 其类似于链表
heap 对象
heap 对象的创建
操作系统对于内存heap段是采用链表进行管理的 操作系统有一个记录空闲内
存地址的链表 当收到程序的申请时 会遍历链表 寻找第一个空间大于所申请的
heap节点 然后将该节点从空闲链表中删除 并将该节点的空间分配给程序
申请大小
栈 stack 在windows下 栈是由低地址扩展的数据结构 是一块连续的内存区
域(栈顶上的地址和栈的最大容量是系统预先规定好的) 在windows下 栈的大
小是2M 如果申请的空间超出了栈的剩余空间的时候 就overflow 因此 能获
得栈的空间较小
堆 heap 堆是向高地址扩展的数据结构 是不连续的区域 这是由于系统是用链
表来存储的空闲内存地址的 自然是不连续的 而链表的遍历方向是由低地址向
高地址 堆的大小受限于计算机系统中有效的虚拟内存 因此 堆获得的空间比较
灵活 也比较大
碎片问题
对于堆来讲,频繁的new/delete势必会造成内存空间的不连续,从而造成大量
的碎片,使程序效率降低。对于栈来讲,则不会存在这个问题,因为栈是先进
后出的队列,他们是如此的一一对应,以至于永远都不可能有一个内存快从栈
中弹出
分配方式
- 堆都是动态分配的
- 栈有两种分配方式 静态分配和动态分配
1.静态分配是编译器完成的 比如局部变量的分配
2.动态分配是alloc函数进行分配的 但是栈的动态分配和堆是不同的 他的
动态分配由编译器进行释放 无需我们手工实现
分配效率
- 栈是机器系统提供的数据结构 计算机会在底层堆栈提供支持 分配专门的寄
存器放栈的地址 压栈出栈都有专门的指令执行 这就决定了栈的效率比较高
- 堆是C/C++函数库提供的 机制比较复杂
一个由C/C++编译的程序占用的内存分为以下几个部分
1.栈区(stack) 由编译器自动分配释放 释放函数的参数值 局部变量的值等
2.堆区(heap) 由程序员分配和释放 若程序员不释放 程序结束时可能由OS
回收
3.全局区(静态区) 全局变量和静态变量的存储是放在一块的 初始化的全局
变量和静态变量在一块区域 未初始化的全局变量 未初始化的静态变量在相邻
另一块区域
4.文字常量区 常量字符串就是放在这里
5.程序代码区 存放函数体的二进制代码

NSString 内存
@"xxx" 方法生成的字符串分配在常量区 系统自动管理内存 在栈区
initWithFormat: 和 stringWithFormat: 方法生成的字符串分配在堆区
NSString *a0 = @"aaa";
NSString *a1 = [NSString stringWithString:a0];
NSString *a2 = [[NSString alloc] initWithString:a0];
NSString *a3 = [[NSString alloc] initWithFormat:@"%@", a0];
NSString *a4 = [[NSString alloc] initWithFormat:@"aaa"];
NSString *a5 = [[NSString alloc] initWithFormat:@"b%@", a0];
NSString *a6 = [[NSString alloc] initWithString:a5];
NSString *a7 = [[NSString alloc] initWithString:a3];
NSLog(@"\na0=~~~~%p\na1=~~~~%p\na2=~~~~%p\na3=~~~~%p\na4=~~~~%p\na5=~~~~%p\na6=~~~~%p\na7=~~~~%p", a0, a1, a2, a3, a4, a5, a6, a7);
打印结果:
a0=~~~~0x107208078
a1=~~~~0x107208078
a2=~~~~0x107208078
a3=~~~~0xa000000006161613
a4=~~~~0xa000000006161613
a5=~~~~0xa000000616161624
a6=~~~~0x60000004d6e0
a7=~~~~0x60000004d3e0
(lldb) p a0
(__NSCFConstantString *) $0 = 0x0000000107208078 @"aaa"
(lldb) p a1
(__NSCFConstantString *) $1 = 0x0000000107208078 @"aaa"
(lldb) p a2
(__NSCFConstantString *) $2 = 0x0000000107208078 @"aaa"
(lldb) p a3
(NSTaggedPointerString *) $3 = 0xa000000006161613 @"aaa"
(lldb) p a4
(NSTaggedPointerString *) $4 = 0xa000000006161613 @"aaa"
(lldb) p a5
(NSTaggedPointerString *) $5 = 0xa000000616161624 @"baaa"
(lldb) p a6
(__NSCFString *) $6 = 0x000060000004d6e0 @"baaa"
(lldb) p a7
(__NSCFString *) $7 = 0x000060000004d3e0 @"aaa"
(lldb)

网友评论