C++内存管理

C++程序运行的环境(内存布局)

在这里插入图片描述
堆区(heap area)
存放new出来的对象。一般由程序员分配和释放,若程序员不释放,程序运行结束时由操作系统回收。

栈区(stack area)
利用栈实现函数的调用,每个函数对应一个栈桢,调用函数时栈桢入栈,调用结束时栈桢出栈。
栈桢包含以下内容:

  • 参数和局部变量

  • 函数的返回地址
    也就是函数执行完成后从哪里开始继续执行后面的代码

  • 一些需要保存的寄存器
    例如 ebp、ebx、esi、edi 等。之所以要保存寄存器的值,是为了在函数退出时能够恢复到函数调用之前的场景,继续执行上层函数。

静态数据区:
在这里插入图片描述

代码区
存放编译完成以后的机器码
这个内存区域是只读的,不会再修改,但也不绝对。现代语言的运行时已经越来越动态化,除了保存机器码,还可以存放中间代码,并且还可以在运行时把中间代码编译成机器码,写入代码区。

堆vs栈

申请方式手动自动
碎片问题new/delete会造成碎片问题栈是一个先进后出的队列,进出一一对应,不会产生碎片
分配方式堆都是动态分配(没有静态分配的堆)栈有静态分配和动态分配,静态分配由编译器完成(如局部变量分配),动态分配由alloca函数分配,但栈的动态分配的资源也是由编译器进行释放,无需程序员动手实现
生长方向堆向高地址方向增长。栈向低地址方向增长
缓存方式栈使用的是一级缓存, 它们通常都是被调用时处于存储空间中,调用完毕立即释放;堆则是存放在二级缓存中,速度要慢些。
内存管理机制系统有一个记录空闲内存地址的链表,当系统收到程序申请时,遍历该链表,寻找第一个空间大于申请空间的堆结点,将该结点空间分配给程序只要栈的剩余空间大于所申请空间,系统为程序提供内存,否则报异常提示栈溢出

举例说明

#include <stdio.h>
char *str1 = "c.biancheng.net";  //字符串在常量区。不会随着 func() 的运行结束而销毁,str1在全局数据区
int n;  //全局数据区
char* func(){
    char *str = "C语言";  //字符串在常量区,str在栈区
    return str;
}
int main(){
    int a;  //栈区
    char *str2 = "01234";  //字符串在常量区,str2在栈区
    char *pstr = func();  //栈区
    int b;  //栈区
}

内存泄露

添加链接描述

内存对齐

什么是内存对齐?

现代计算机中内存空间都是按照字节划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但是实际的计算机系统对基本类型数据在内存中存放的位置有限制,它们会要求这些数据的首地址的值是某个数k(通常它为4或8)的倍数,这就是所谓的内存对齐。

为什么要进行内存对齐?——提高数据读取效率
比如当我们保证所有double类型的数据的地址对齐成8的倍数时,我们就可以用一次内存操作来读写值,否则可能需要两次内存访问,因为对象可能放在两个8字节的内存块中

对齐原则:任何K字节的基本对象的地址必须是K的倍数

具体如何对齐举例一:

//32位系统
#include<stdio.h>
struct
{
    int i;    
    char c1;  
    char c2;  
}x1;

struct{
    char c1;  
    int i;    
    char c2;  
}x2;

struct{
    char c1;  
    char c2; 
    int i;    
}x3;

int main()
{
    printf("%d\n",sizeof(x1));  // 输出8
    printf("%d\n",sizeof(x2));  // 输出12
    printf("%d\n",sizeof(x3));  // 输出8
    return 0;
}

在这里插入图片描述

举例二:

class A{
int a //4
short b //4
int c //4
short d //4
}

A的实例占16字节

怎么优化?——调整字段的存放顺序

class A{
int a //4
int c //4
short b //2
short d //2
}

现在一共占12字节

现在B继承A

class B : A{
short e 
}

B类的实例占多少字节?
——20字节
编译器为啥不把e和d挨着放呢?
因为如果放一起的话,A类对象仍然认为d独占4字节,所以会把e也取出来,造成错误。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值