前言
sizeof()
和 strlen()
在平时开发中使用的频率相对没那么高,个人觉得简单了解它们的用法及区别就 OK 了;最近刚好遇到一个用 sizeof()
计算结构体占用内存空间的问题,我们顺便也扯一扯这个吧。
这篇文章首先我们简单讲一下 sizeof()
和 strlen()
的区别,然后了解下基本变量类型在 iOS 中占用多少内存空间,然后再扯一下如何计算结构体占用的内存空间大小,进而引申出字节对齐这个机制;最后总结在编写结构体的时需要注意的点。
sizeof() 跟 strlen() 的区别
简单来说: sizeof()
是运算符,在编译时期计算参数占用多少内存空间大小;strlen()
是一个函数,在运行时计算字符串的长度;
所以我感觉就是两个东西,也不是很清楚这两个有什么联系,不知道为什么会有这样奇怪的题目,可能我还没 get 到点吧,有人知道还望请告知。
基本数据类型在 iOS 中占用内存空间大小问题
这里直接用表格列举出来吧:
基本数据类型 | 32 位系统占用字节数 | 64位系统占用字节数 |
---|---|---|
char | 1 | 1 |
char * | 4 | 8 |
short int | 2 | 2 |
int | 4 | 4 |
unsigned int | 4 | 4 |
long | 4 | 8 |
long long | 8 | 8 |
unsigned long long | 8 | 8 |
float | 4 | 4 |
Double | 8 | 8 |
结构体占用内存空间大小问题
为了更加清晰了解结构体占用内存空间的问题,我们先来分析下面代码示例:
typedef struct
{
char member1; //1字节
short member2; //2字节
int member3; //4字节
}Family;
typedef struct
{
char member1; //1字节
int member3; //4字节
short member2; //2字节
}Family2;
NSLog(@"Family size is %zd",sizeof(Family));
NSLog(@"Family2 size is %zd",sizeof(Family2));
//Family size is 8
//Family2 size is 12
看到 Log 结果,我们可能有两个疑问:
- 为什么 size 结果不是 7
- 两个结构体成员变量是一样的,顺序不同为什么会导致 size 不一样
这里其实涉及到了内存对齐,我们就简单说下需要内存对齐的原因以及内存对齐的规则,再详细的知识点可以看下文末的参考链接。
首先变量存放在内存中是不能随意存的,需要有一定的规则,在特定的地址才能存放特定的变量,这就导致变量在内存空间上不是简单的排序排列,需要一定的规则,为了达到这个规则,我们就需要内存对齐。
内存对齐的原因:
- 某些平台只能在特定的地址访问特定类型的数据
- 提高存取数据的速度
结构体内存对齐规则,摘抄自 一张图理解内存对齐 :
- 结构体中的第一个成员的首地址也即是结构体变量的首地址。
- 结构体中的每一个成员的首地址相对于结构体的首地址的偏移量(offset)是该成员数据类型大小的整数倍。
- 结构体的总大小是对齐模数(对齐模数等于#pragma pack(n)所指定的n与结构体中最大数据类型的成员大小的最小值)的整数倍。
通过上面规则我们可以很轻松的计算出上面代码结构体占用的大小:
typedef struct
{
char member1; //1字节
short member2; //2字节
int member3; //4字节
}Family;
// 对于这个结构体:1+`1`+2+4 = 8字节 `1` 是补齐字节
typedef struct
{
char member1; //1字节
int member3; //4字节
short member2; //2字节
}Family2;
// 对于这个结构体:1+`3`+4+2+`2` = 12字节,`3` 和 `2` 是补齐字节
这里可能有点晦涩难懂,大家可以具体看看这篇博客:C语言 - 结构体所占字节数 ,我这里再摘抄的话,也没什么意思;
反正对于计算结构体占用内存大小,大家需要注意有内存对齐这个东西就好了。
编写结构体注意事项
对于结构体占用内存空间这个,不是我们程序的性能瓶颈,但是学完这个面试题,我觉得掌握以下两个点挺好的:
- 写结构体时,尽量将成员变量按照占用内存空间从小到大排序
- 面对一些源码时,可以知道手动内存补齐这东西
例如下面 RunLoop 源码, _padding[3]
这个成员变量没有实际的意义,只是用来内存补齐的。
struct __CFRunLoopMode {
CFRuntimeBase _base;
pthread_mutex_t _lock; /* must have the run loop locked before locking this */
CFStringRef _name;
Boolean _stopped;
char _padding[3];
CFMutableSetRef _sources0;
CFMutableSetRef _sources1;
CFMutableArrayRef _observers;
CFMutableArrayRef _timers;
//……
};
总结
这篇文章只是简单的说了下 sizeof()
跟 strlen()
的区别,然后聊了下将最近遇到结构体计算内存空间大小的问题,认识到了还有内存对齐这个东西;
感觉这篇有点水,主要还是说引申一些知识点,增加下知识的广度吧,对于我自己还是学到了一些的,关于更深度的东西,依旧,参考文献很优秀。
网友评论