分析NSArray内存变化和NSMutableArray扩容

前言

OC对象是通过alloc来申请内存空间的,底层其实调用了malloc函数在堆区分配了一块内存空间,p指针指向该堆区
Person *p = [Person alloc] init];

  1. NSarray的内存分析

NSArray *arr = @[@"tom",@"jack",@"rose",@"eva",@"jj"]; NSLog(@"%ld",arr.count);
定义一个简单的数组,看一下内存

(lldb) x/100xb arr
0x608000078d00: 0xd8 0x0d 0x9a 0x02 0x01 0x00 0x00 0x00
0x608000078d08: 0x05 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x608000078d10: 0x98 0xd0 0xb7 0x01 0x01 0x00 0x00 0x00
0x608000078d18: 0xb8 0xd0 0xb7 0x01 0x01 0x00 0x00 0x00
0x608000078d20: 0xd8 0xd0 0xb7 0x01 0x01 0x00 0x00 0x00
0x608000078d28: 0xf8 0xd0 0xb7 0x01 0x01 0x00 0x00 0x00
0x608000078d30: 0x18 0xd1 0xb7 0x01 0x01 0x00 0x00 0x00
0x608000078d38: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x608000078d40: 0x90 0x14 0x9a 0x02 0x01 0x00 0x00 0x00
0x608000078d48: 0x80 0x12 0x00 0x00 0x01 0x00 0x00 0x00
0x608000078d50: 0x13 0x00 0x05 0x00 0x12 0x00 0x00 0x00
0x608000078d58: 0x00 0x00 0x04 0x03 0x0c 0x20 0x80 0x00
0x608000078d60: 0x10 0x40 0x00 0x04
(lldb) po 0x01029a0dd8
__NSArrayI

(lldb) po 0x0101b7d098
tom

可以看到第二行的0x05表示数组的长度,从第三行开始就是数组里面的数据

补充知识

x/100xb arr的意思是: 读取100个字节,并以16进制显示

  • 第一个x是memory read的简写(通过help x可以看出来)
  • 第二个x代表16进制
  • b代表字节

x/100xw arr的意思是: 读取100个字,并以16进制显示(64位cpu里面,一个字=4个字节)

2.NSMutableArray的扩容

数组在内存中的存储可以按照下图理解,首先会在内存中请求开辟一块堆空间用来存储数组的长度,容量以及数组元素首地址的指针等等,然后再开辟一块堆空间用来存放数据(线性表的顺序存储)。当容量不够的时候,会重新开辟另外的空间,然后将数据复制到新的空间里,最后再将旧的空间释放掉。


分析NSArray内存变化和NSMutableArray扩容_第1张图片
屏幕快照 2017-07-29 下午6.26.43.png

下面结合代码和lldb来看看在内存中到底是怎样变化的

  • 首先给NSArray写一个分类,这个分类的主要作用就是找到数组中元素的首地址
-(void *)dataFirstAddress
{
    void * address = (__bridge void *)self;
    return  *((void **)address + 5);
}

分类中代码的意思是:从该地址开始,往后便移40个字节(void **表示8个字节,+5表示以该类型为准,往后移动5次,所以就是5 * 8=40个字节),为什么移动5次,下面会解释。0x0104aa60b8

  • 为什么加5?看下面代码
NSMutableArray * arr = [NSMutableArray arrayWithCapacity:0];
    NSLog(@"数据地址是:%p",@"100");
    for (int i = 0; i < 7; i++) {
        [arr addObject:@"100"];
    }
    NSLog(@"%ld",arr.count);

下面是lldb里面的内容

2017-07-29 18:44:35.222 NSArray分析[5240:2951263] 数据地址是:0x10198f0b8
(lldb) x/100xb arr
0x600000243c60: 0x00 0x2e 0x7b 0x02 0x01 0x00 0x00 0x00
0x600000243c68: 0x07 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x600000243c70: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x600000243c78: 0x0a 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x600000243c80: 0x08 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x600000243c88: 0xd0 0x02 0x28 0x00 0x80 0x60 0x00 0x00
0x600000243c90: 0xf0 0x24 0x7b 0x02 0x01 0x00 0x00 0x00
0x600000243c98: 0x8c 0x07 0x00 0x00 0x01 0x00 0x00 0x00
0x600000243ca0: 0x17 0x5f 0x55 0x49 0x56 0x69 0x65 0x77
0x600000243ca8: 0x43 0x6f 0x6e 0x74 0x72 0x6f 0x6c 0x6c
0x600000243cb0: 0x65 0x72 0x42 0x6f 0x74 0x74 0x6f 0x6d
0x600000243cb8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x600000243cc0: 0xad 0xbe 0x8c 0xbe
(lldb) x/100xb 0x6080002802d0
0x6080002802d0: 0xb8 0xf0 0x98 0x01 0x01 0x00 0x00 0x00
0x6080002802d8: 0xb8 0xf0 0x98 0x01 0x01 0x00 0x00 0x00
0x6080002802e0: 0xb8 0xf0 0x98 0x01 0x01 0x00 0x00 0x00
0x6080002802e8: 0xb8 0xf0 0x98 0x01 0x01 0x00 0x00 0x00
0x6080002802f0: 0xb8 0xf0 0x98 0x01 0x01 0x00 0x00 0x00
0x6080002802f8: 0xb8 0xf0 0x98 0x01 0x01 0x00 0x00 0x00
0x608000280300: 0xb8 0xf0 0x98 0x01 0x01 0x00 0x00 0x00
0x608000280308: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x608000280310: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x608000280318: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x608000280320: 0xd4 0x79 0xf7 0x01 0x01 0x00 0x00 0x00
0x608000280328: 0x1f 0x2e 0xf7 0x01 0x01 0x00 0x00 0x00
0x608000280330: 0x00 0x00 0x00 0x00
(lldb) po 0x10198f0b8
100

可以看到,第二行0x07代表的是数组的长度,第五行就表示数组数据元素的首地址,那么我要找到数据的首地址,就要往后找40个字节,这就是上面分类里面代码的意思。

  • 然后再看下面代码
NSMutableArray * arr = [NSMutableArray arrayWithCapacity:0];
    NSLog(@"数组数据元素的首地址是:%p",arr.dataFirstAddress);
    for (int i = 0; i < 10; i++) {
        [arr addObject:@"100"];
        NSLog(@"数组长度是:%zd 数组数据元素的首地址是:%p",arr.count,arr.dataFirstAddress);
    }
    NSLog(@"%ld",arr.count);

下面是lldb里面的内容

2017-07-29 18:54:13.159 NSArray分析[5261:2965310] 数组数据元素的首地址是:0x0
2017-07-29 18:54:13.159 NSArray分析[5261:2965310] 数组长度是:1 数组数据元素的首地址是:0x60000000a840
2017-07-29 18:54:13.160 NSArray分析[5261:2965310] 数组长度是:2 数组数据元素的首地址是:0x60000000a840
2017-07-29 18:54:13.160 NSArray分析[5261:2965310] 数组长度是:3 数组数据元素的首地址是:0x608000036680
2017-07-29 18:54:13.160 NSArray分析[5261:2965310] 数组长度是:4 数组数据元素的首地址是:0x608000036680
2017-07-29 18:54:13.160 NSArray分析[5261:2965310] 数组长度是:5 数组数据元素的首地址是:0x608000045040
2017-07-29 18:54:13.160 NSArray分析[5261:2965310] 数组长度是:6 数组数据元素的首地址是:0x608000045040
2017-07-29 18:54:13.160 NSArray分析[5261:2965310] 数组长度是:7 数组数据元素的首地址是:0x60000008ffa0
2017-07-29 18:54:13.160 NSArray分析[5261:2965310] 数组长度是:8 数组数据元素的首地址是:0x60000008ffa0
2017-07-29 18:54:13.161 NSArray分析[5261:2965310] 数组长度是:9 数组数据元素的首地址是:0x60000008ffa0
2017-07-29 18:54:13.161 NSArray分析[5261:2965310] 数组长度是:10 数组数据元素的首地址是:0x60000008ffa0
(lldb)

可以看到,随着数组中元素的增加,容量不够用,就会开辟新的空间来存放数据。

你可能感兴趣的:(分析NSArray内存变化和NSMutableArray扩容)