代码的内存消耗
1.C++内存分为四个区:
- 代码区: 存放函数体的二进制代码。
- 全局区(静态区,常量区): 全局变量和静态变量都存储在全局区,全局对象在程序启动时创建,程序结束时销毁;局部static在第一次使用时被创建,在程序结束时销毁。
- 栈区: 栈区用来存放局部变量,局部变量在块内所定义的地方被创建,在离开块时被销毁。
- 堆区: 堆区用来存放动态内存,动态内存对象的生存期被程序控制,必须程序员自己区销毁它。
内存四区地址的分配如下图:
2.C++的内存管理
我们写的C++程序运行时所需的内存空间分为固定部分和可变部分:
固定部分的内存消耗时是不会随着代码运行产生变化的,可变部分则是会产生变化的。 更具体一些,一些由C++编译的程序占用的内存分为以下几个部分:
- 栈区:由编译器自动分配释放,存放函数的参数值、局部变量的值等,其操作方式类似于数据结构中的栈。
- 堆区: 一般由程序员分配释放,若程序员不自己释放,程序结束时由os收回
- 未初始化数据区: 存放未初始化的全局变量和静态变量。
- 初始化数据区: 存放已经初始化的全局变量和静态变量。
- 程序代码区: 存放函数体的二进制代码。
固定部分代码区和数据区所占内存都是固定的,而且占用空间非常小,那么看运行时消耗的内存主要是看可变部分。
在可变部分中,栈区间的数据在代码块执行结束之后,系统会自动回收,而堆区间数据是需要程序员自己回收,所以也就是造成内存泄漏的发源地。
3.如何计算程序占用多大内存
想要算出程序会占用多少内存就要了解自己定义的数据类型的大小,如下:
为什么32位编译器指针占4个字节,而64位编译器指针占8个字节?
因为1个字节占8个比特,4个字节占32比特,可存放数据大小为2^32 ,即4G空间大小,即可以寻找4G空间大小的内存地址。 64位操作系统同理,可存放数据大小为2^64,即16777216TB空间(但由于主板和cpu限制电脑所支持内存一般最大只有16GB)。
由于现在使用的计算机都是64位,使用内存都超过了4GB,因此64位编译器使用8个字节的指针才能寻找所有内存地址。
4.内存对齐
内存对齐的两个原因:
- 平台原因:不是所有硬件平台都能访问任意内存地址上的任意数据,某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。为了同一个程序可以在多平台上运行,需要内存对齐。
- 硬件原因:经过内存对其后,CPU访问内存的速度大大提升。
看如下例子:
struct node{
int num;
char cha;
}st;
int main() {
int a[100];
char b[100];
cout << sizeof(int) << endl;
cout << sizeof(char) << endl;
cout << sizeof(a) << endl;
cout << sizeof(b) << endl;
cout << sizeof(st) << endl;
}
输出结果为:
4
1
400
100
8 //num一个是int型,一个是char型,所占字节数应该是5,这里确是8,就是因为内存对其。
我们来看一下内存对齐和非内存对其产生的效果区别:
CPU读取内存不是一次读取单个字节,而是一块一块的来读取内存,块的大小可以是2,4,8,16个字节,具体取多少取决于硬件。
假设CPU内存划分为4字节大小的块,要读取一个4字节大小的int型数据,来看一下这两种情况下CPU的工作量。
①内存对齐的情况,如图:
一字节的char占用了4个字节,空了3个字节的内存地址,int数据从地址4开始。
此时,直接将地址4,5,6,7处的四个字节数据读取即可。
②没有内存对齐的情况,如图:
char型数据和int型数据挨在一起,该int数据从地址1开始,那么CPU想要读这个数据的话来看看需要几步操作:
- 因为CPU是四个字节四个字节来寻址,首先CPU读取0,1,2,3处四个字节的数据
- CPU读取4,5,6,7处的四个字节数据
- 合并地址1,2,3,4处四个字节的数据才是本次操作需要的int数据
- 此时一共需要两次寻址,一次合并的操作。
虽然内存对齐浪费了内存资源,但由于计算机内存资源都是很充足的,我们更希望提高运行速度,而内存对齐后可以大大提高CPU访问内存的速度。
编译器一般都会做内存对齐的优化操作,因此,在考虑程序真正占用内存大小的时候,也需要认识到内存对齐的影响。
根据代码随想录为参考整理:https://programmercarl.com/%E5%89%8D%E5%BA%8F/%E5%88%B7%E4%BA%86%E8%BF%99%E4%B9%88%E5%A4%9A%E9%A2%98%EF%BC%8C%E4%BD%A0%E4%BA%86%E8%A7%A3%E8%87%AA%E5%B7%B1%E4%BB%A3%E7%A0%81%E7%9A%84%E5%86%85%E5%AD%98%E6%B6%88%E8%80%97%E4%B9%88%EF%BC%9F.html#%E5%86%85%E5%AD%98%E5%AF%B9%E9%BD%90