浅谈C++内存使用------静态Vs动态 堆Vs栈 智能指针

C++内存概述

  在C++中,内存被分为五个区域:堆、栈、自由存储区、静态/全局存储区和常量存储区。

  • 静态存储区:静态内存用来保存局部static对象、类static数据成员、以及定义在任何函数之外的变量(全局变量)。
  • 栈内存:栈内存用来保存定义在函数内的非static对象。
  • 堆内存:使用new关键字开辟的内存空间就位于堆内存,有程序员释放(不由编译器负责),一般一个new对应一个delete,一个new[]对应一个delete[],如果程序员没有释放,在程序结束时,系统会自动收回资源。
  • 自由存储区:是*alloc分配的内存空间即位于自由空间,使用free来释放
  • 常量存储区:一块特殊的存储区,里面存放常量,不允许修改。
      堆和自由空间其实是一个整体的内存池,属于同一块区域,new的底层实现调用了malloc,new可以看做是malloc智能化的高级版本。

堆VS栈

  堆内存和栈内存是内存中两块不同的区域,他们在诸多方面既有区别又有联系:

  • 管理方式:
    • 中的资源有程序员来控制,有时我们忘记释放内存,会造成内存泄漏(memory leak);有时某内存单元中的数据尚有指针在引用,我们就是放了该内存,就会产生引用非法内存的指针。
    • 资源由编译器自动管理,无需手动控制。
  • 系统响应:
    • ,对于栈,系统中有一个记录空闲内存地址的指针,当系统收到程序申请时,遍历该链表,寻找第一个空间大于申请空间的堆节点,将该节点从空闲链表中删除,并将其分配给程序。如果该堆内存块的大小恰好等于申请空间大小,则直接将首地址返回给用户;如果内存块的大小大于所申请大小,则将此块分裂,将剩余部分的堆内存留在可用堆内存中,以“堆链表”的形式和其他未被分配的内存关联。如果整个堆链表内都未找到满足大小的堆内存块,系统将会给“堆链表”链接一个更大的区域供其使用,若这一步骤依然失败,malloc则将返回NULL,并向程序员报错。
    • ,只要栈的剩余空间大于所申请空间,系统为程序提供内存,否则报出异常提示栈溢出。
  • 空间大小
    • :堆不是连续的内存区域,因为系统使用链表来存储空闲空间,堆大小受限于计算机系统中有效的虚拟内存(32位系统理论上是4G),所以堆的空间比较灵活,比较大。
    • :栈是一块连续的内存区域,大小是操作系统预定好的,是一个编译时就确定的常数。如果申请空间超过栈的剩余空间,将提示overflow。因此能从栈获得的空间较小。
  • 碎片问题
    • :对于堆,频繁的使用new/delete会造成大量碎片,是程序效率降低。
    • :对于栈,是一个先进后出的队列,进出一一对应,不会产生碎片。
  • 生长方向
    • :堆向上,由低地址向高地址扩展。
    • :栈向下,由高地址向低地址扩展。
  • 分配效率
    • :堆是由new分配的内存,都是动态分配,一般速度较慢,而且容易产生碎片,不用使用方便。
    • :栈由系统自动分配,既有动态分配也有静态分配。速度较快,但程序员无法控制。

malloc和free

malloc

  根据标准C库函数的定义,malloc具有如下如下原型:

void* malloc(size_t size);

这个函数要实现的功能是在系统中分配一段连续的可用的内存,具体要求如下:

  • malloc分配的内存大小至少为size参数所指定的字节数。
  • malloc的返回值是一个指针,指向一段可用内存的起始地址。
  • 多次调用malloc所分配的地址不能有重叠部分,除非某次malloc所分配的地址被释放。
  • malloc应尽快完成内存分配并返回(不使用NP-hard的内存分配算法)。
  • 实现malloc时应实现内存大小调整和内存释放函数(realloc,free)

free

  free函数用来释放之前调用malloc、calloc、realloc所分配的内存空间,具有如下原型:

void free(void *ptr);

  free的实现并不是看上去那么简单,要进行free,首先要解决两个关键问题:

  • 1.如何验证传入的地址是有效的,即确定是通过malloc方式分配的数据区首地址。要解决这一问题,首先要确定改地址在之前malloc所分配的区域内,即在first_block和当前break指针范围内;其次这个地址确实是之前通过malloc分配的。
  • 2.如何解决碎片问题。

new和delete

  在C++中,动态内存的管理师通过一对运算符来完成的。new:在动态内存中为对象分配空间并返回一个指向该对象的指针,我们可以选择对对象进行初始化。delete:接受一个动态对象的指针,销毁该对象,并释放与之关联的内存。
malloc和new的区别

  • malloc/free是标准库函数,new/delete是C++运算符;
  • malloc失败返回空,new失败抛出异常;
  • new/delete会调用构造、析构函数,malloc/free不会,所以他么无法满足动态对象的要求。
  • new返回有类型的指针,malloc返回无类型的指针。

智能指针

  为了更容易也更安全的使用动态内存,C++新的标准库提供了智能指针类型来管理动态对象。它与正常指针类似,重要的区别是它负责自动释放所指的对象。因为智能指针也是一个类,当超出类的作用域时,类会自动调用析构函数,析构函数会自动释放资源。所以智能指针的作用原理就是在函数结束时自动释放内存空间,而不需要手动释放内存空间。

  • shared_ptr允许多个指针指向同一个对象,该对象何其相关的资源会在“最后一个引用被撤销”的时候释放。它使用计数机制来表明资源被几个指针共享,可用通过成员函数use_count()来查看资源的所有者个数。
  • unique_ptr实现独占拥有或者严格拥有概念,保证同一时间内只有一个智能指针可以指向该对象。对于避免资源泄露特别有用
  • weak_ptr是一种不控制生命周期的智能指针,它指向一个shared_ptr管理的对象。进行该对象的内存管理的是强引用的shared_ptr,weak_ptr只是提供了对管理对象的一个访问手段。weak_ptr设计的目的是为了配合shared_ptr而引入的之中智能指针来协助shared_ptr工作,它只可以从一个shared_ptr或另一个weak_ptr对象构造,他的构造和析构函数不会引起计数的增加或减少。weak_ptr是用来解决shared_ptr相互引用时的思索问题,如果两个shared_ptr相互引用,那么这两个指针的引用计数永远不能下降为0,资源永远不会释放。
  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值