C++内存分配管理

  一、内存分配方式

 1、程序运行前(编译后)

       代码区  存放CPU执行的机器指令,即编写的所有代码

                     代码区是共享的,其原因是对于频繁被执行的程序,只需要在内存中有一份代码即可

                     代码区是只读的,放置程序意外第修改了它的指令

       全局区(包含常量存储区、静态存储区)

           (1) 静态存储区:存放静态变量(static)、全局变量

           (2)常量存储区:字符串常量、const修饰的全局常量

    2、程序运行后

        栈区 由编译器自动分配,存放函数的参数值、局部变量等;函数结束时,系统自动回收。

                 栈内存分配运算内置于处理器的指令集中,效率很高,但分配的内存空间有限。

        堆区  由程序员分配释放,程序员不释放,程序结束时由操作系统回收。

                C++中主要利用new在堆区开辟内存(该块内存又称为自由存储区)

       堆和栈的区别参考:c++ 内存管理_AITBOOK-CSDN博客

  二、C++中可能出现的内存问题及解决办法

  1 缓冲区溢出

     由程序员自己编写Buffer类来管理缓冲区,自动记住使用缓冲区的大小,通过成员函数(不是裸指针)来修改缓冲区。          

  2 野指针

     野指针:指针变量指向非法的内存空间,如:使用没有申请的内存,或者已经释放的内存

     解决办法:(1)在使用内存前,检查指针是否为空指针NULL

                       (2)一个指针指向一个对象,当对象销毁时,该指针应该自动置为NULL,而不需要                        对象通知重置。C++11提供shared_ptr/weak_ptr(下面内存泄漏部分详细阐述)可以解                         决,我们在编写程序时,尽量使用智能指针,避免野指针。

   空指针定义 int *p = NULL 表示指针变量指向内存中编号为0的空间

                       空指针指向的内存是不可访问的,0~255号内存被系统占用

          NULL本质是宏#define NULL 0,这里的0既可以表示整型常量,又可以表示指针常量。

          这带 来一些问题,例如:无法区分void fun(int a) 与void func(int* a)。

          C++11 中提供nullptr表示空指针,nullptr是指针类型,不能转换成整型类型,建议使用

 3 重复释放

    C++中一个指针被重复delete,编译时不会报错,在运行时才报错。

    浅拷贝:一个类中有属性m_A(指针数据)开辟在堆区,对象P2通过对象P1进行拷贝构造创建,P1和P2的属性的属性指向同一块内存。在函数运行结束后,P1和P2都调用析构函数释放时(释放顺序:先进后出),先释放P2(此时堆区内存已经释放),再释放P1(堆区内存又释放一次)

    可以利用深拷贝来解决浅拷贝带来的问题,我们只需重载拷贝构造函数,通过P1构造P2时,在堆区重新开辟空间,放P2的属性m_A。

   重载拷贝构造时需要注意的问题:形参一般是常量引用,如 const Person &p

      设置为常量,防止出错,只读 (拷贝操作,值必然不能改变)

      必须设置为引用, 否则传参时,自动调用拷贝构造,拷贝一个临时副本,导致拷贝构造函数无限的递归,最终使栈溢出。

 4 内存泄漏

    未能及时释放不再使用的内存(借东西不还,程序功能),失去对内存的控制(并不是物理内存消失),常指堆区内存泄漏,因为堆是动态分配的,由程序员控制的,使用不当就会出现内存泄漏问题。

解决办法:(1)动态内存的申请和释放必须配对,即new-delete 和 malloc-free

                   (2)shared_ptr指针 管理动态申请new的对象的销毁。

shared_ptr共享指针原理:若某块内存被多个指针共享,使用计数器表示该对象被几个指针调用。一般通过use_count()函数查看有几个指针;通过release()释放内存,每当一个指针释放,计数减1,当计数减为0时,自动释放该块内存,从而避免内存泄漏。          

 5  不配对的new和delete

     一般把new[]换成vector或array开辟连续存储空间

 6 内存碎片

对于堆来讲,频繁的new/delete会造成内存空间的不连续,产生大量碎片,使程序效率降低。

对于栈来讲,不会存在这个问题,因为栈是先进后出的,压根不会存在某个内存块从栈中间弹出。

解决办法:(1) 内存池技术,相同大小或者大小接近的内存都放到同一个内存池,这样从内存池的                         每个内存块之间浪费的内存会非常小或者没有浪费。

                       优点:一次性先从操作系统OS申请一大块内存,所以,在为每个对象分配内存时                                     候,就不 用再跟OS交互了,能够提升效率。

                  (2)内存池向系统申请内存时都以页为单位进行申请大块内存,内存池对外分配内存也                          以优先使用使用率最高的内存块,这样会有更高的效率将整个内存块归还系统

 本文参考C/C++内存分配管理_一只大笨猫的博客-CSDN博客_c++内存分配

                C++内存碎片的处理机制_wingnet-CSDN博客

                C++内存管理(面试版)_知愚的博客-CSDN博客                

                C/C++的内存碎片、内存泄漏以及内存越界问题的解决方案_daphnis的博客-CSDN博客

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值