mirror of
https://github.com/NohamR/knowledge-kit.git
synced 2026-05-25 04:17:17 +00:00
docs: clang 插件开发
This commit is contained in:
@@ -470,6 +470,15 @@ class_rw_t *personMetaClassData = personClass->metaClass()->data();
|
||||
```
|
||||
|
||||
## 五、 内存对齐
|
||||
内存对齐是指数据在内存中存储时按照一定规则对齐到特定的地址上。在 iOS 开发中,内存对齐是为了提高内存访问的效率和性能。内存对齐的原因主要包括以下几点:
|
||||
1. 提高访问速度:内存对齐可以使数据在内存中的存储更加高效,因为大部分计算机体系结构都要求数据按照特定的边界对齐,这样可以减少内存访问的次数,提高访问速度。CPU访问非对齐的内存时需要进行多次拼接。
|
||||
如下图,比如需要读取从[2, 5]的内存,需要分别读取两次,然后还需要做位移的运算,最后才能得到需要的数据。这中间的损耗就会影响访问速度。
|
||||
<img src="https://github.com/FantasticLBP/knowledge-kit/raw/master/assets/MemoryAlignReason.png" style="zoom:30%">
|
||||
|
||||
2. 为了方便移植。CPU是一块块的进行进行内存访问。有一些硬件平台不允许随机访问,只能访问对齐后的内存地址,否则会报异常。
|
||||
很多 CPU(如基于 Alpha,IA-64,MIPS,和 SuperH 体系的)拒绝读取未对齐数据。当一个程序要求这些 CPU 读取未对齐数据时,这时 CPU 会进入异常处理状态并且通知程序不能继续执行。举个例子,在 ARM,MIPS,和 SH 硬件平台上,当操作系统被要求存取一个未对齐数据时会默认给应用程序抛出硬件异常。
|
||||
3. 硬件要求:某些硬件平台对于数据的访问有特定的要求,例如ARM架构的处理器对于某些数据类型的访问需要按照特定的对齐方式进行
|
||||
4. 数据结构优化:内存对齐也有助于优化数据结构的布局,使得数据在内存中的存储更加紧凑和高效。
|
||||
|
||||
Demo1
|
||||
|
||||
@@ -492,7 +501,7 @@ NSLog(@"%zd", malloc_size((__bridge const void *)person)); // 16
|
||||
NSLog(@"%zd", sizeof(struct Person_IMPL)); // 16
|
||||
```
|
||||
|
||||
isa 指针8字节 + int _age 4字节 + _hright 字节 = 16 字节
|
||||
`isa 指针 8字节` + `int _age 4字节` + `_hright 字节` = 16 字节
|
||||
|
||||
Demo2
|
||||
|
||||
@@ -513,15 +522,17 @@ struct Person_IMPL {
|
||||
};
|
||||
|
||||
Person *person = [[Person alloc] init];
|
||||
NSLog(@"%zd", malloc_size((__bridge const void *)person)); // 32
|
||||
NSLog(@"%zd", sizeof(struct Person_IMPL)); // 24
|
||||
NSLog(@"%zd", malloc_size((__bridge const void *)person)); // 32
|
||||
```
|
||||
|
||||
isa 指针8字节 + int _age 4字节 + _hright 字节 + _no 4 字节 = 20 字节,因为存在内存对齐,因为结构体本身对齐内存对齐,必须为8的倍数,所以占据24个字节的内存。
|
||||
`isa 指针8字节` + `int _age 4字节` + `_height 4字节` + `_no 4 字节` = 20 字节,因为存在内存对齐,因为结构体本身对齐内存对齐,必须为8的倍数,所以占据24个字节的内存。结构体成员变量,内存对齐时,对齐基数必须是各个成员变量中最大字节数的一个。
|
||||
|
||||
结构体占据24字节,为什么运行起来后通过 `malloc_size` 得到32个字节?这个涉及到运行时内存对齐。规定 **iOS 中内存对齐以 16 的倍数为准**。
|
||||
|
||||
Demo
|
||||
|
||||
|
||||
Demo
|
||||
|
||||
```objectivec
|
||||
void *temp = malloc(4);
|
||||
@@ -531,7 +542,7 @@ NSLog(@"%zd", malloc_size(temp));
|
||||
|
||||
可以看到 malloc 申请了4个字节,但是打印却看到16个字节。
|
||||
|
||||
查看源码也可以出来分配内存最小是以16的倍数为基准进行分配的。
|
||||
查看 libmalloc源码也可以出来分配内存最小是以16的倍数为基准进行分配的。
|
||||
|
||||
```c
|
||||
#define NANO_MAX_SIZE 256 /* Buckets sized {16, 32, 48, 64, 80, 96, 112, ...} */
|
||||
@@ -539,4 +550,8 @@ NSLog(@"%zd", malloc_size(temp));
|
||||
|
||||
为什么系统是由16字节对齐的?
|
||||
|
||||
成员变量占用8字节对齐,每个对象的第一个都是 isa 指针,必须要占用8字节。举例一个极端 case,假设 n 个对象,其中 m 个对象没有成员变量,只有 isa 指针占用8字节,其中的 n-m个对象既有 isa 指针,又有成员变量。每个类交错排列,那么 CPU 在访问对象的时候会耗费大量时间去识别具体的对象。很多时候会取舍,这个 case 就是时间换空间。以16字节对齐,会加快访问速度(参考链表和数组的设计)
|
||||
成员变量占用8字节对齐,每个对象的第一个都是 isa 指针,必须要占用8字节。举例一个极端 case,假设 n 个对象,其中 m 个对象没有成员变量,只有 isa 指针占用8字节,其中的 n-m个对象既有 isa 指针,又有成员变量。每个类交错排列,那么 CPU 在访问对象的时候会耗费大量时间去识别具体的对象。很多时候会取舍,这个 case 就是时间换空间。以16字节对齐,会加快访问速度(参考链表和数组的设计)
|
||||
|
||||
|
||||
|
||||
Todo: 研究探索 glibc 源代码,分析内存对齐、内存分配的原理
|
||||
Reference in New Issue
Block a user