热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

c++内存管理_C/C++内存管理概述

CC赋予程序员管理内存的自由,是CC语言特色,虽然这引入了复杂度和危险性,但另一方面,它也增加了控制力和灵活性,

C/C++赋予程序员管理内存的自由,是C/C++语言特色,虽然这引入了复杂度和危险性,但另一方面,它也增加了控制力和灵活性,是C/C++独特之处,亦是强大之处。

动态内存分配器

libc是c语言的标准程序库,glibc是c标准程序库在linux系统下的一个实现。动态内存分配器(例如glibc ptmalloc)是介于操作系统和应用程序之间的一个程序库,从kernel程序员的视角看来,它属于应用程序库,因为free掉的内存不一定真正返还系统,而应用程序员看来,它又属于偏系统级程序,因为free掉之后,应用程序似乎已经完成了归还。

虚拟存储

操作系统管理物理内存,运行在操作系统上的应用程序,拥有独立的虚拟地址空间,操作系统提供从虚拟地址到物理地址之间的映射,这种转换是自动的,需要硬件(寄存器)和软件(页表)配合完成,虚拟内存是计算机的一个核心概念,基于虚拟内存而不是物理内存,使得运行在单机上的多个进程之间共享存储变得可能。我们用c/c++开发应用,使用的地址都是虚拟地址,如果访问的虚拟地址不在内存里,则产生缺页中断,操作系统会自动换页,而这个过程是有成本的,惩罚还不低,所以,我们应该了解和利用局部性,这对指令和数据同样有效。

linux进程的虚拟地址空间

下面的两张图描绘了linux进程的虚拟地址空间,理解这个很重要。

66814f667fbc388369b494b99819f044.png

cd8a4c84379933be1d2bd091b6a535b5.png

CACHE

CPU、寄存器、(多级)缓存、内存、磁盘IO各级之间的速度至少相差一个量级,没有什么是cache解决不了的。

我们应该利用局部性,编写和选择局部性好的算法,比如基于有序数组的二分查找往往比rbtree更快。

应用程序内存管理

用c/c++编写应用程序,经常接管动态内存分配和回收,主要基于以下几方面的考虑。

  1. 快,希望动态内存的请求能够得到迅速满足,动态内存分配器吞吐率越大越好。

  2. 省,减少内存碎片,包括内碎片(chunk块内部填充)和外碎片,有更好的内存利用率。快和省往往是此消彼长的,内存管理常需平衡折中。

  3. 稳,期望更好的安全保障,比如避免泄漏、悬垂指针等。

基于以上需求,形形色色的内存管理技巧被发掘出来。

比如nginx基于pool的技术,让每个request从单独的pool对象里分配内存,pool通过移动指针(快)满足动态内存请求,request处理过程中不需要为每个分配的chunk做释放动作,只需要在request处理完成阶段释放pool,从而释放过程中申请的每个chunk,从而拥有更好的安全性。

小对象分配,如果void *p = malloc(1)分配一个字节,实际上因为有首尾部和填充,所以实际上消耗远远大于一个字节,这体现在用malloc_usable_size(p)返回值远大于1字节。有效载荷跟实际占用的比值应该是越大越好,而小对象有效载荷比较小,所以有必要优化它,这对于频繁且大量分配小对象的应用程序是有效的,有很多针对小对象的分配优化方法,比如经典的《C++设计新思维》提到的小对象分配器。

对象池,针对一类对象的专用分配器,因为libc的动态内存分配器是为通用目的而设计的,它在最广泛情况下表现良好,但不是每种情况都表现最好,所以针对特定场景和需求而专门设计内存分配策略,是有效的。如果应用程序,有一类对象,最多只分配1000个,便可以用这类对象池,它几乎同时满足了快、省、稳的要求。

预分配、有些业务场景,会在服务启动时候把内存都分配好,运行过程中,不再动态申请,这在游戏服务器等业务中经常出现,初听有些奇怪,实际上,它也带来一些好处,比如程序运行过程中,你不用担心OOM的问题,因为理论上它的内存占用量是直线,而且基于预分配的策略,内存泄漏的问题也会少很多。

语言和工具支持

c语言支持hook malloc、free、realloc等接口,这样你可以从比较低的层次干预和统计内存分配。

c++支持operator new/new[]、operator delete/delete[]、以及类的operator new/delete重载。

c++的标准库容器,比如vector、list、map等,都支持传入自定义allocator,你可以接管内存配置,而不限于默认分配器。

COW(Copy On Write)写时拷贝是一项能节省拷贝的技术,fork出来的进程也用到了cow,如果要全量拷贝,那fork的返回会延迟很多。

为了防止内存泄漏,有时候会借助RAII技术。

引用计数是实现智能指针的关键技术,需要区分弱引用和强引用,以及shared和unique,所有权的概念。

ptmalloc可以开启一些统计选项,这可以为排错提供帮助。

libc的动态内存分配器默认是ptmalloc,你也可以用google的tcmalloc,以及jemalloc等动态内存分配器替换。

监控和查找内存泄漏问题,你可以借助valgrind工具,不过valgrind对代码有要求,只有符合它期望的程序才能valgrind干净,不然误报会比较多。

内存拷贝是我们应该竭力减少的,不做任何多余的拷贝,很多程序profiling会发现,内存、字符串相关的函数经常出现在top list。




推荐阅读
  • 本文详细介绍了云服务器API接口的概念和作用,以及如何使用API接口管理云上资源和开发应用程序。通过创建实例API、调整实例配置API、关闭实例API和退还实例API等功能,可以实现云服务器的创建、配置修改和销毁等操作。对于想要学习云服务器API接口的人来说,本文提供了详细的入门指南和使用方法。如果想进一步了解相关知识或阅读更多相关文章,请关注编程笔记行业资讯频道。 ... [详细]
  • 图解redis的持久化存储机制RDB和AOF的原理和优缺点
    本文通过图解的方式介绍了redis的持久化存储机制RDB和AOF的原理和优缺点。RDB是将redis内存中的数据保存为快照文件,恢复速度较快但不支持拉链式快照。AOF是将操作日志保存到磁盘,实时存储数据但恢复速度较慢。文章详细分析了两种机制的优缺点,帮助读者更好地理解redis的持久化存储策略。 ... [详细]
  • 计算机存储系统的层次结构及其优势
    本文介绍了计算机存储系统的层次结构,包括高速缓存、主存储器和辅助存储器三个层次。通过分层存储数据可以提高程序的执行效率。计算机存储系统的层次结构将各种不同存储容量、存取速度和价格的存储器有机组合成整体,形成可寻址存储空间比主存储器空间大得多的存储整体。由于辅助存储器容量大、价格低,使得整体存储系统的平均价格降低。同时,高速缓存的存取速度可以和CPU的工作速度相匹配,进一步提高程序执行效率。 ... [详细]
  • 如何提高PHP编程技能及推荐高级教程
    本文介绍了如何提高PHP编程技能的方法,推荐了一些高级教程。学习任何一种编程语言都需要长期的坚持和不懈的努力,本文提醒读者要有足够的耐心和时间投入。通过实践操作学习,可以更好地理解和掌握PHP语言的特异性,特别是单引号和双引号的用法。同时,本文也指出了只走马观花看整体而不深入学习的学习方式无法真正掌握这门语言,建议读者要从整体来考虑局部,培养大局观。最后,本文提醒读者完成一个像模像样的网站需要付出更多的努力和实践。 ... [详细]
  • 本文介绍了操作系统的定义和功能,包括操作系统的本质、用户界面以及系统调用的分类。同时还介绍了进程和线程的区别,包括进程和线程的定义和作用。 ... [详细]
  • 这是原文链接:sendingformdata许多情况下,我们使用表单发送数据到服务器。服务器处理数据并返回响应给用户。这看起来很简单,但是 ... [详细]
  • Android中高级面试必知必会,积累总结
    本文介绍了Android中高级面试的必知必会内容,并总结了相关经验。文章指出,如今的Android市场对开发人员的要求更高,需要更专业的人才。同时,文章还给出了针对Android岗位的职责和要求,并提供了简历突出的建议。 ... [详细]
  • 如何用UE4制作2D游戏文档——计算篇
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了如何用UE4制作2D游戏文档——计算篇相关的知识,希望对你有一定的参考价值。 ... [详细]
  • 开发笔记:计网局域网:NAT 是如何工作的?
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了计网-局域网:NAT是如何工作的?相关的知识,希望对你有一定的参考价值。 ... [详细]
  • CentOS 7部署KVM虚拟化环境之一架构介绍
    本文介绍了CentOS 7部署KVM虚拟化环境的架构,详细解释了虚拟化技术的概念和原理,包括全虚拟化和半虚拟化。同时介绍了虚拟机的概念和虚拟化软件的作用。 ... [详细]
  • WebSocket与Socket.io的理解
    WebSocketprotocol是HTML5一种新的协议。它的最大特点就是,服务器可以主动向客户端推送信息,客户端也可以主动向服务器发送信息,是真正的双向平等对话,属于服务器推送 ... [详细]
  • Go语言实现堆排序的详细教程
    本文主要介绍了Go语言实现堆排序的详细教程,包括大根堆的定义和完全二叉树的概念。通过图解和算法描述,详细介绍了堆排序的实现过程。堆排序是一种效率很高的排序算法,时间复杂度为O(nlgn)。阅读本文大约需要15分钟。 ... [详细]
  • GPT-3发布,动动手指就能自动生成代码的神器来了!
    近日,OpenAI发布了最新的NLP模型GPT-3,该模型在GitHub趋势榜上名列前茅。GPT-3使用的数据集容量达到45TB,参数个数高达1750亿,训练好的模型需要700G的硬盘空间来存储。一位开发者根据GPT-3模型上线了一个名为debuid的网站,用户只需用英语描述需求,前端代码就能自动生成。这个神奇的功能让许多程序员感到惊讶。去年,OpenAI在与世界冠军OG战队的表演赛中展示了他们的强化学习模型,在限定条件下以2:0完胜人类冠军。 ... [详细]
  • svnWebUI:一款现代化的svn服务端管理软件
    svnWebUI是一款图形化管理服务端Subversion的配置工具,适用于非程序员使用。它解决了svn用户和权限配置繁琐且不便的问题,提供了现代化的web界面,让svn服务端管理变得轻松。演示地址:http://svn.nginxwebui.cn:6060。 ... [详细]
  • SpringBoot整合SpringSecurity+JWT实现单点登录
    SpringBoot整合SpringSecurity+JWT实现单点登录,Go语言社区,Golang程序员人脉社 ... [详细]
author-avatar
mobiledu2502889415
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有