C/C++中有关内存问题的汇总

一、C/C++类型大小问题

类型32位环境下所占字节数64位环境下所占字节数
char11
short int22
int44
long int48
long long int88
float44
double88
char*44
int *44

特别地,NULL占用4字节。

二、数据存储问题

(一)、C/C++内存中五大区域

其在内存中分配的位置图如下。
内存分布

1、堆(Heap)

存放着由操作malloc/free,new/delete分配/释放的内存(不太安全的内存管理方式)。堆可以动态地扩展和收缩,这个区域通常较大,并向高地址扩展。动态内存的生存期人为决定,使用灵活。缺点是容易造成内存泄漏(Memory Leakage),频繁操作会产生大量内存碎片。

(1)、内存碎片(Memory Fragment)

内存碎片分为两种:外部碎片和内部碎片。

①、外部碎片(External Memory Fragment)

外部碎片指的是还没有被分配出去(不属于任何进程),但由于太小了无法分配给申请内存空间的新进程的内存空闲区域。
外部碎片是出于任何已分配区域或页面外部的空闲存储块。这些存储块的总和可以满足当前申请的长度要求,但是由于它们的地址不连续或其他原因,使得系统无法满足当前申请。
多道可变连续分配只有外部碎片。

②、内部碎片(Internal Memory Fragment)

内部碎片就是已经被分配出去(能明确指出属于哪个进程)却不能被利用的内存空间;
内部碎片是处于区域内部或页面内部的存储块。占有这些区域或页面的进程并不使用这个存储块。而在进程占有这块存储块时,系统无法利用它。直到进程释放它,或进程结束时,系统才有可能利用这个存储块。
单道连续分配只有内部碎片。多道固定连续分配既有内部碎片,又有外部碎片。

③、内存碎片减少的方法(Solutions)

采用控制页边界对齐内存字节对齐、将相邻空闲内存块连接起来、内存池等先进的内存管理机制。

2、栈(Stack)

存放函数的参数值局部变量,函数执行结束时会被自动释放。栈内存分配运算内置于处理器的指令集中,效率高,但是容量有限。(栈方便用来保存/恢复调用现场,可以把其看成一个暂时保存和交换数据的区域)

3、BSS段(Block Started by Symbol Segment)

用来存放程序未初始化的全局变量。不保存在硬盘上,只是记录数据所需空间的大小,程序开始执行之前,由内核进行初始化为0。BSS段属于静态内存分配,即程序一开始就将其清零了。

4、数据段(Data Segment)

用来存放程序已初始化的全局变量。数据段属于静态内存分配。其中static静态变量存放在数据段中,而非栈区。

5、代码段(Code Segment/Text Segment)

用来存放程序执行代码。这部分区域的大小在程序运行前就已经确定,通常为只读(某些架构也允许代码段为可写,即允许修改程序),也有可能包含一些只读的常量,例如字符串常量等。

三、结构体和数组的问题

如下所示,假如系统的数据存储方式为小端模式(Little Endian),三个输出应该是什么?

#include <iostream>

struct data {
       uint16_t a;
       uint8_t b;
       uint16_t c;
}*example;

int main(int argc, char* argv[]) {
       uint8_t num[] = { 1,2,3,4,5,6,7 };
       example =(struct data*)num;
       printf("%x %x %x", example->a, example->b, example->c);
       system("pause");
       return 0;
}

输出结构是 0x0201 0x03 0x0605,这是为什么呢?看下面的数据存放图。

在这里插入图片描述

可以得出结构体中16位的a等于0x0201,8位的b等于0x03,16位的c等于0x0605。由于内存对齐,成员b只用到了低字节0x03,0x04就被舍弃了(实际上还存在内存里,但用不到,除非在b的地址加上一字节偏移,如使用*(&(example->b)+1) 就能读到0x04)。

参考链接:
C/C++内存分配方式与存储区

已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: 技术黑板 设计师:CSDN官方博客 返回首页