内存五大区
-
内核区
,其实CPU调度的一块内存区域 -
栈区(stack)
,其使用SP寄存器寻址,所以速度很快,存的是函数的局部变量和形参。 -
堆区(heap)
,频繁的new/delete势必会造成内存空间的不连续,从而造成大量碎片,使程序效率降低,其不能安名字访问,只能通过地址指针访问 -
静态区/全局区(.bss)
,存放的是未初始化的全局变量和静态变量 -
常量区(.data)
,是只读数据段/读写数据段,存的是已初始化的全局变量和静态变量 -
代码区(.text)
,也叫text段,只读存储区,代码从磁盘加载进内存的区域
栈示例
void stackDemo(){
NSLog(@"************栈区************");
// 栈区
int a = 10;
int b = 20;
NSObject *object = [NSObject new];
NSLog(@"a == \t%p",&a);
NSLog(@"b == \t%p",&b);
NSLog(@"object == \t%p",&object);
}
2021-10-26 14:40:11.892128+0800 001---五大区Demo[28799:12704013] a == 0x16bda732c
2021-10-26 14:40:11.892159+0800 001---五大区Demo[28799:12704013] b == 0x16bda7328
2021-10-26 14:40:11.892185+0800 001---五大区Demo[28799:12704013] object == 0x16bda7320
(ViewController *) self = 0x0000000152f07230
(SEL) _cmd = "stackDemo"
(int) a = 10
(int) b = 20
(NSObject *) object = 0x0000600002240400
(lldb) x/8gx 0x16bda7320
0x16bda7320: 0x0000600002240400 0x0000000a00000014
0x16bda7330: 0x000000010405724b 0x0000000152f07230
0x16bda7340: 0x000000016bda7380 0x0000000104055e1c
0x16bda7350: 0x000000016bda7358 0x0000600002258730
(lldb) po (SEL)0x000000010405724b
"testStack"
建一个示例函数,打印所有局部变量的内存地址,然后打印object
附近的函数栈内存,命令x/8gx
,参数和局部变量是如何入栈的。本人特意对比了一下模拟器和真机结果顺序是一样的都如下:
栈内存是有栈保护的,不同的函数栈内存不一样,在使用完后要进行必要的栈平衡操作。
堆示例
- (void)heapDemo{
NSLog(@"************堆区************");
// 堆区
NSObject *object1 = [NSObject new];
NSObject *object2 = [NSObject new];
NSObject *object3 = [NSObject new];
NSObject *object4 = [NSObject new];
NSLog(@"object1 %p= %@",&object1,object1);
NSLog(@"object2 %p= %@",&object2,object2);
NSLog(@"object3 %p= %@",&object3,object3);
NSLog(@"object4 %p= %@",&object4,object4);
}
2021-10-26 15:37:05.358658+0800 001---五大区Demo[29048:12741205] ************堆区************
2021-10-26 15:37:05.359288+0800 001---五大区Demo[29048:12741205] object1 0x16b9d7328=
2021-10-26 15:37:05.359414+0800 001---五大区Demo[29048:12741205] object2 0x16b9d7320=
2021-10-26 15:37:05.359523+0800 001---五大区Demo[29048:12741205] object3 0x16b9d7318=
2021-10-26 15:37:05.359616+0800 001---五大区Demo[29048:12741205] object4 0x16b9d7310=
(ViewController *) self = 0x0000000157808fa0
(SEL) _cmd = "heapDemo"
(NSObject *) object1 = 0x0000600003ca80b0
(NSObject *) object2 = 0x0000600003ca80a0
(NSObject *) object3 = 0x0000600003ca8090
(NSObject *) object4 = 0x0000600003ca80c0
可以看到对象的创建,会在堆内存分配空间,然后栈内存中通过指针地址指向这片内存空间达到访问堆内存的目的。堆内存只要没有被持有,就变成脏内存,就有可能被覆盖。
静态区/常量区示例
文件A_begin
static int personNum = 100;
文件A_end
文件B_begin
int clA; // 未初始化的全局变量
int clB = 10; // 已初始化的全局变量
static int bssA; // 未初始化的全局静态变量
static NSString *bssStr1; // 未初始化的全局静态变量
static int bssB = 10; // 已初始化的全局静态变量
static NSString *bssStr2 = @"cooci"; // 已初始化的全局静态变量
static NSString *lgname = @"KC"; // 已初始化的全局静态变量
NSLog(@"************静态区************");
NSLog(@"clA == \t%p",&clA);
NSLog(@"bssA == \t%p",&bssA);
NSLog(@"bssStr1 == \t%p",&bssStr1);
NSLog(@"************常量区************");
NSLog(@"clB == \t%p",&clB);
NSLog(@"bssB == \t%p",&bssB);
NSLog(@"bssStr2 == \t%p",&bssStr2);
NSLog(@"************静态区安全测试************");
// 100 可以修改
// 只针对文件有效 -
NSLog(@"vc:%p--%d",&personNum,personNum); // 100
personNum = 10000;
NSLog(@"vc:%p--%d",&personNum,personNum); // 10000
[[LGPerson new] run]; // 100 + 1 = 101
NSLog(@"vc:%p--%d",&personNum,personNum); // 10000
[LGPerson eat]; // 102
NSLog(@"vc:%p--%d",&personNum,personNum); // 10000
[[LGPerson new] run]; // 100 + 1 = 101
[[LGPerson alloc] cate_method];
文件B_end
输出:
2021-10-26 16:40:01.736512+0800 001---五大区Demo[29337:12786203] ************静态区************
2021-10-26 16:40:01.737909+0800 001---五大区Demo[29337:12786203] clA == 0x104524f14
2021-10-26 16:40:01.737935+0800 001---五大区Demo[29337:12786203] bssA == 0x104524f18
2021-10-26 16:40:01.737961+0800 001---五大区Demo[29337:12786203] bssStr1 == 0x104524f20
2021-10-26 16:40:01.737993+0800 001---五大区Demo[29337:12786203] ************常量区************
2021-10-26 16:40:01.738017+0800 001---五大区Demo[29337:12786203] clB == 0x104524ef8
2021-10-26 16:40:01.738039+0800 001---五大区Demo[29337:12786203] bssB == 0x104524f08
2021-10-26 16:40:01.738059+0800 001---五大区Demo[29337:12786203] bssStr2 == 0x104524f00
2021-10-26 16:40:01.738083+0800 001---五大区Demo[29337:12786203] ************静态区安全测试************
2021-10-26 16:40:01.738106+0800 001---五大区Demo[29337:12786203] vc:0x104524f0c--100
2021-10-26 16:40:01.738127+0800 001---五大区Demo[29337:12786203] vc:0x104524f0c--10000
2021-10-26 16:40:01.738159+0800 001---五大区Demo[29337:12786203] LGPerson内部:-0x104524ef0--101
2021-10-26 16:40:01.756948+0800 001---五大区Demo[29337:12786203] vc:0x104524f0c--10000
2021-10-26 16:40:01.757060+0800 001---五大区Demo[29337:12786203] LGPerson内部:LGPerson-0x104524ef0--102
2021-10-26 16:40:01.757112+0800 001---五大区Demo[29337:12786203] vc:0x104524f0c--10000
2021-10-26 16:40:01.757173+0800 001---五大区Demo[29337:12786203] LGPerson内部:-0x104524ef0--103
通过静态区和常量区的内存大小可以看出,静态区在常量区的上面(也就是在高地址空间)。但是有意思的是全局静态变量在跨文件访问的时候,会分配不同的地址空间存储,相当于两个变量,可以理解为:静态全局变量是文件内独一份,跨文件之后会进行地址拷贝一份。