iOS内存分布

基本概念

RAM

随机存取存储器(random access memory,RAM)又称作“随机存储器”,是与CPU直接交换数据的内部存储器,也叫主存(内存)。

  • 存储单元的内容可按需随意取出或存入,且存取的速度很快,与存储单元的位置无关。
  • 这种存储器在断电时将丢失其存储内容,故主要用于存储 短时间使用 的程序。
  • 通常作为操作系统或其他正在运行中的程序的临时数据存储媒介。

ROM

ROM是只读存储器(Read-Only Memory)的简称,是一种只能读出事先所存数据的固态半导体存储器。

  • 所存数据稳定,断电后所存数据也不会改变。
  • 其结构较简单,读出较方便,因而常用于存储各种固定程序和数据。
  • 为便于使用和大批量生产,进一步发展了各种可读写存储器,如快闪存储器(Flash memory)。

在计算机系统运行应用时,会把APP从ROM里面拷贝到内存(RAM),然后从内存里面执行代码。运行的应用程序的数据都是保存在内存中的,不同类型的数据,保存的内存区域不同。

iOS的内存

iOS的内存分布与C语言的类似,分为:

  1. 代码区
  2. 文字常量区
  3. 全局区/静态区(Static)
  4. 堆区(Heap)
  5. 栈区(Stack)

代码区

存放函数的二进制代码

常量区

存放常量字符串以及其他定义的常量,程序结束系统释放

全局区/静态区(Static)

全局变量和静态变量的存储是放在一起的,初始化的全局变量和静态变量存放在一块区域,未初始化的全局变量和静态变量在相邻的另一块区域,程序结束后由系统释放。

注意:全局区又可分为:

未初始化全局区: bss段

初始化全局区:data段

举例:int a——未初始化的;int a = 10——已初始化的。

1
2
int a = 10; // 全局初始化区
char *p; // 全局未初始化区

堆区(Heap)

  • 堆区的内存分配使用的是alloc,代码中创建的对象一般都存在堆中
  • 需要程序猿管理内存;
  • ARC的内存的管理,是编译器再便宜的时候自动添加 retain、release、autorelease;
  • 堆区的地址是从低到高分配)

栈区(Stack)

  • 存放的局部变量、先进后出、一旦出了作用域就会被销毁;函数跳转地址,现场保护等;
  • 程序猿不需要管理栈区变量的内存;
  • 栈区地址从高到低分配;

具体代码分析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// 分别创建相同的全局变量

NSInteger a = 100;
NSString *str1 = @"123";
const NSString *str2 = @"123";
NSString *strEm1 = @"";
NSString *strEm2 = @"";
NSInteger b = 200;

@implementation ViewController

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
NSString *str3 = @"123";
NSString *strEm3 = @"";
NSMutableString *mutStr = [[NSMutableString alloc] init];
NSString *strEm4 = [NSString string];
NSString *strEm5 = [[NSString alloc] init];
NSLog(@"str1: %p---%p---%@", str1, &str1, str1.class);
NSLog(@"str2: %p---%p---%@", str2, &str2, str2.class);
NSLog(@"str3: %p---%p---%@", str3, &str3, str3.class);
NSLog(@"strEm1:%p---%p---%@", strEm1, &strEm1, strEm1.class);
NSLog(@"strEm2:%p---%p---%@", strEm2, &strEm2, strEm2.class);
NSLog(@"strEm3:%p---%p---%@", strEm3, &strEm3, strEm3.class);
NSLog(@"strEm4:%p---%p---%@", strEm4, &strEm4, strEm4.class);
NSLog(@"strEm5:%p---%p---%@", strEm5, &strEm5, strEm5.class);
NSLog(@"mutStr:%p---%p---%@", mutStr, &mutStr, mutStr.class);
NSLog(@"a: %p", &a);
NSLog(@"b: %p", &b);
}
@end

打印结果如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
str1:  0x10e117070---0x10e118048---__NSCFConstantString
str2: 0x10e117070---0x10e118050---__NSCFConstantString
str3: 0x10e117070---0x7ffee1ae7fe8---__NSCFConstantString

strEm1:0x10e117090---0x10e118058---__NSCFConstantString
strEm2:0x10e117090---0x10e118060---__NSCFConstantString
strEm3:0x10e117090---0x7ffee1ae7fe0---__NSCFConstantString

strEm4:0x10e713338---0x7ffee1ae7fd0---__NSCFConstantString
strEm5:0x10e713338---0x7ffee1ae7fc8---__NSCFConstantString
mutStr:0x60400025caa0---0x7ffee1ae7fd8---__NSCFString
a: 0x10e118040
b: 0x10e118068

由此可以看出:

  1. 直接以@"创建的字符串对象都存储在字符串常量区,而且相同的字符串只会在内存中存在一份。其他用到此字符串的变量/常量指针指向这块内存。

  2. 全局变量储存在全局区,如 abstr1str2strEm1strEm2,其中str1str2strEm1strEm2是指针,指向的字符串常量对象在常量区。

  3. str3strEm3是局部变量,内存在栈区,指向的字符串常量对象在常量区。

  4. strEm4strEm5也是局部变量,内存在栈区,但是其指向的对象是用类创建的空字符串(类型__NSCFConstantString),是预先创建好的,存储在全局区。

  5. mutStr可变字符串指针,内存在栈区;指向的可变字符串对象在堆区。一般创建的对象都存储在堆区,指针变量指向这些对象,局部变量本身的内存在栈区。

  6. @"123"本身就是常量,所以 str2之前的 const的写与不写没什么区别。