内存基础
1. 进制
在基数为 R 的进制中,包含 R 个数字符号, 分别是 0, 1, 2, …, R-1 一个整数n位、小数m位的R进制数字,可以表示为:
其中, 是第 位上的数字符号,满足 。 同时,也可以用连加符号来表示:
1.1 二进制
二进制是基数为 2 的进制系统,使用两个数字符号:0 和 1。每一位上的权重是 2 的幂次方。
如:
1.2 八进制、十六进制与二进制的换算
八进制和十六进制是计算机常用的进制。
- 八进制(Oct,简写O):使用八个数字符号:0, 1, 2, 3, 4, 5, 6 和 7。
- 十六进制(Hex,简写H):使用十六个数字符号:0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E 和 F。
由于 和 ,八进制和十六进制的每一位可以直接对应二进制的三位和四位:
八进制:
0 = 0b000 1 = 0b001 2 = 0b010 3 = 0b011
4 = 0b100 5 = 0b101 6 = 0b110 7 = 0b111
十六进制:
0 = 0b0000 1 = 0b0001 2 = 0b0010 3 = 0b0011
4 = 0b0100 5 = 0b0101 6 = 0b0110 7 = 0b0111
8 = 0b1000 9 = 0b1001 A = 0b1010 B = 0b1011
C = 0b1100 D = 0b1101 E = 0b1110 F = 0b1111
2. 比特、字节与字
- 比特(bit):计算机的最小数据单位,只有两个取值:0或1
- 字节(Byte):一个字节由8个比特组成,即
1Byte = 8bit - 字(Word):计算机进行数据处理和存储时,作为一个单元的一组二进制数位。
- 字的长度(即一个字包含的比特位数)取决于计算机的硬件架构。早期16位计算机系统中,一个字是16比特位,在现在的32位和64位计算机系统中,一个字分别是32比特和64比特。
- 计算机的 CPU 在处理数据时,通常以字为单位进行操作。较大的字长意味着 CPU 一次能够处理更多的数据,从而提高计算机的运算速度和效率
3. 内存与地址
- 内存是计算机中用于暂时存储数据和程序的部件,当你打开一个程序,程序及其相关数据就会被加载到内存中,CPU 才能对它们进行处理。
- 内存地址:内存地址是内存中每个存储单元(每个字节)的唯一编号,CPU通过地址获取数据存储在内存中的位置,进而进行读写操作。
注:对于32位系统,由于地址总线宽度为 32 位,我们用 32 个二进制位来表示地址,通常写成十六进制也就是 0x00000000 到 0xFFFFFFFF 的形式。类似地,64位系统用 64 个二进制位来表示地址,通常写成十六进制也就是 0x0000000000000000 到 0xFFFFFFFFFFFFFFFF 的形式。
C++的内存结构:

3.1 C++进程的内存布局
- 代码段 (
.text):编译后的机器指令、函数代码,只读共享 - 常量段 (
.rodata):字符串字面量、const全局常量,只读 - 全局 / 静态数据段 (
.data/.bss).data:初始化全局变量、静态局部变量.bss:未初始化全局 / 静态变量,程序启动清零
- 堆 (
Heap) - 共享库、内存映射区域
- 栈 (
Stack)(每个线程独立栈) - 内核空间(用户程序不可访问)
其中,堆和栈是程序运行时动态分配的内存区域。堆用于动态分配内存,从低地址往高地址增长;而栈用于函数调用和局部变量的存储,从高地址往低地址增长;两者中间留大片空闲虚拟内存,避免碰撞。
3.2 栈的管理规则
- 操作系统预先分配固定大小:Windows 默认 1MB,Linux 默认 8MB,编译链接时可改栈大小
- 自动生命周期:进入函数分配栈帧,函数 return 自动销毁栈帧,无需手动释放
- 分配极快:只修改栈寄存器 rsp/sp,无系统调用
- LIFO 后进先出,栈帧连续内存,无碎片
- 缺点:空间极小,大数组、深度递归会触发 栈溢出 Stack Overflow
3.3 堆的管理规则
- 空间巨大:使用进程剩余虚拟内存,上限由操作系统 / 物理内存限制
- 手动管理:
- C:malloc 申请,free 释放
- C++:new 申请,delete 释放;忘记释放造成内存泄漏;重复释放、野指针崩溃
- 分配慢:需要堆管理器查找空闲块、维护链表元数据,频繁分配释放产生内存碎片
- 生命周期不受函数限制:函数退出堆内存不会自动销毁,必须手动释放
- 进程全局共享,所有线程共用同一块堆,并发分配需要加锁,存在竞争


