热门标签 | 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。




推荐阅读
  • 优化ListView性能
    本文深入探讨了如何通过多种技术手段优化ListView的性能,包括视图复用、ViewHolder模式、分批加载数据、图片优化及内存管理等。这些方法能够显著提升应用的响应速度和用户体验。 ... [详细]
  • 深入解析 Apache Shiro 安全框架架构
    本文详细介绍了 Apache Shiro,一个强大且灵活的开源安全框架。Shiro 专注于简化身份验证、授权、会话管理和加密等复杂的安全操作,使开发者能够更轻松地保护应用程序。其核心目标是提供易于使用和理解的API,同时确保高度的安全性和灵活性。 ... [详细]
  • 深入解析Android自定义View面试题
    本文探讨了Android Launcher开发中自定义View的重要性,并通过一道经典的面试题,帮助开发者更好地理解自定义View的实现细节。文章不仅涵盖了基础知识,还提供了实际操作建议。 ... [详细]
  • 1:有如下一段程序:packagea.b.c;publicclassTest{privatestaticinti0;publicintgetNext(){return ... [详细]
  • 本文详细介绍了Java编程语言中的核心概念和常见面试问题,包括集合类、数据结构、线程处理、Java虚拟机(JVM)、HTTP协议以及Git操作等方面的内容。通过深入分析每个主题,帮助读者更好地理解Java的关键特性和最佳实践。 ... [详细]
  • 本文详细介绍了如何构建一个高效的UI管理系统,集中处理UI页面的打开、关闭、层级管理和页面跳转等问题。通过UIManager统一管理外部切换逻辑,实现功能逻辑分散化和代码复用,支持多人协作开发。 ... [详细]
  • 从 .NET 转 Java 的自学之路:IO 流基础篇
    本文详细介绍了 Java 中的 IO 流,包括字节流和字符流的基本概念及其操作方式。探讨了如何处理不同类型的文件数据,并结合编码机制确保字符数据的正确读写。同时,文中还涵盖了装饰设计模式的应用,以及多种常见的 IO 操作实例。 ... [详细]
  • 网易严选Java开发面试:MySQL索引深度解析
    本文详细记录了网易严选Java开发岗位的面试经验,特别针对MySQL索引相关的技术问题进行了深入探讨。通过本文,读者可以了解面试官常问的索引问题及其背后的原理。 ... [详细]
  • 本文探讨了如何在日常工作中通过优化效率和深入研究核心技术,将技术和知识转化为实际收益。文章结合个人经验,分享了提高工作效率、掌握高价值技能以及选择合适工作环境的方法,帮助读者更好地实现技术变现。 ... [详细]
  • 本文详细介绍了在企业级项目中如何优化 Webpack 配置,特别是在 React 移动端项目中的最佳实践。涵盖资源压缩、代码分割、构建范围缩小、缓存机制以及性能优化等多个方面。 ... [详细]
  • 深入理解Java中的volatile、内存屏障与CPU指令
    本文详细探讨了Java中volatile关键字的作用机制,以及其与内存屏障和CPU指令之间的关系。通过具体示例和专业解析,帮助读者更好地理解多线程编程中的同步问题。 ... [详细]
  • 本文详细介绍如何通过修改配置文件来隐藏Apache、Nginx和PHP的版本号,从而增强网站的安全性。我们将提供具体的配置步骤,并解释这些设置的重要性。 ... [详细]
  • 探讨了如何解决Ajax请求响应时间过长的问题。本文分析了一个从服务器获取少量数据的Ajax请求,尽管服务器已经对JSON响应进行了缓存,但实际响应时间仍然不稳定。 ... [详细]
  • MySQL PMM:MyISAM 和 Aria 存储引擎的性能优化
    本文探讨了 MyISAM 和 Aria 存储引擎在 MySQL 中的关键性能指标,包括密钥缓冲区效率、页面缓存读写性能以及事务日志同步策略。通过优化这些参数,可以显著提升数据库的整体性能。 ... [详细]
  • 本文探讨了Java编程的核心要素,特别是其面向对象的特性,并详细介绍了Java虚拟机、类装载器体系结构、Java类文件和Java API等关键技术。这些技术使得Java成为一种功能强大且易于使用的编程语言。 ... [详细]
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社区 版权所有