C系代码内存处理优化分析

【C#学习笔记】内存管理 自动内存管理自动内存管理是CLR在托管执行过程中提供的服务之一。公共语言运行时的垃圾回收器为应用程序管理内存的分配和释放。对开发人员而言,这就意味着在开发托管应用程序时不必编写执行内存管理任务的代码。自动内存管理可解决常见问题,例如,忘记释放对象并导致内存泄漏,或尝试访问已释放对象的内存。 阅读详情
现象
1 压力测试过程中,发现被测对象性能不够理想,具体表现为:  
进程的系统态CPU消耗20,用户态CPU消耗10,系统idle大约70  
2 用ps -o majflt,minflt -C program命令查看,发现majflt每秒增量为0,而minflt每秒增量大于10000。

初步分析
majflt代表major fault,中文名叫大错误,minflt代表minor fault,中文名叫小错误。
这两个数值表示一个进程自启动以来所发生的缺页中断的次数。
当一个进程发生缺页中断的时候,进程会陷入内核态,执行以下操作:  
检查要访问的虚拟地址是否合法  
查找/分配一个物理页  
填充物理页内容(读取磁盘,或者直接置0,或者啥也不干)  
建立映射关系(虚拟地址到物理地址)  
重新执行发生缺页中断的那条指令  
如果第3步,需要读取磁盘,那么这次缺页中断就是majflt,否则就是minflt。  
此进程minflt如此之高,一秒10000多次,不得不怀疑它跟进程内核态cpu消耗大有很大关系。

分析代码
查看代码,发现是这么写的:一个请求来,用malloc分配2M内存,请求结束后free这块内存。看日志,发现分配内存语句耗时10us,平均一条请求处理耗时1000us 。 原因已找到!  
虽然分配内存语句的耗时在一条处理请求中耗时比重不大,但是这条语句严重影响了性能。要解释清楚原因,需要先了解一下内存分配的原理。  

内存分配的原理
从操作系统角度来看,进程分配内存有两种方式,分别由两个系统调用完成:brk和mmap(不考虑共享内存)。brk是将数据段(.data)的最高地址指针_edata往高地址推,mmap是在进程的虚拟地址空间中(一般是堆和栈中间)找一块空闲的。这两种方式分配的都是虚拟内存,没有分配物理内存。在第一次访问已分配的虚拟地址空间的时候,发生缺页中断,操作系统负责分配物理内存,然后建立虚拟内存和物理内存之间的映射关系。  
在标准C库中,提供了malloc/free函数分配释放内存,这两个函数底层是由brk,mmap,munmap这些系统调用实现的。  
下面以一个例子来说明内存分配的原理:
  
1进程启动的时候,其(虚拟)内存空间的初始布局如图1所示。其中,mmap内存映射文件是在堆和栈的中间(例如libc-2.2.93.so,其它数据文件等),为了简单起见,省略了内存映射文件。_edata指针(glibc里面定义)指向数据段的最高地址。  
2进程调用A=malloc(30K)以后,内存空间如图2:malloc函数会调用brk系统调用,将_edata指针往高地址推30K,就完成虚拟内存分配。你可能会问:只要把_edata+30K就完成内存分配了?事实是这样的,_edata+30K只是完成虚拟地址的分配,A这块内存现在还是没有物理页与之对应的,等到进程第一次读写A这块内存的时候,发生缺页中断,这个时候,内核才分配A这块内存对应的物理页。也就是说,如果用malloc分配了A这块内容,然后从来不访问它,那么,A对应的物理页是不会被分配的。  
3进程调用B=malloc(40K)以后,内存空间如图3.  

  
4进程调用C=malloc(200K)以后,内存空间如图4:默认情况下,malloc函数分配内存,如果请求内存大于128K(可由M_MMAP_THRESHOLD选项调节),那就不是去推_edata指针了,而是利用mmap系统调用,从堆和栈的中间分配一块虚拟内存。这样子做主要是因为brk分配的内存需要等到高地址内存释放以后才能释放(例如,在B释放之前,A是不可能释放的),而mmap分配的内存可以单独释放。当然,还有其它的好处,也有坏处,再具体下去,有兴趣的同学可以去看glibc里面malloc的代码了。  
5进程调用D=malloc(100K)以后,内存空间如图5.  
6进程调用free(C)以后,C对应的虚拟内存和物理内存一起释放  
  

7进程调用free(B)以后,如图7所示。B对应的虚拟内存和物理内存都没有释放,因为只有一个_edata指针,如果往回推,那么D这块内存怎么办呢?当然,B这块内存,是可以重用的,如果这个时候再来一个40K的请求,那么malloc很可能就把B这块内存返回回去了。  
8进程调用free(D)以后,如图8所示。B和D连接起来,变成一块140K的空闲内存。  
9默认情况下:当最高地址空间的空闲内存超过128K时,执行内存紧缩操作(trim)。在上一个步骤free的时候,发现最高地址空闲内存超过128K,于是内存紧缩,变成图9所示。

真相大白
说完内存分配的原理,那么被测模块在内核态cpu消耗高的原因就很清楚了:每次请求来都malloc一块2M的内存,默认情况下,malloc调用mmap分配内存,请求结束的时候,调用munmap释放内存。假设每个请求需要6个物理页,那么每个请求就会产生6个缺页中断,在2000的压力下,每秒就产生了10000多次缺页中断,这些缺页中断不需要读取磁盘解决,所以叫做minflt;缺页中断在内核态执行,因此进程的内核态cpu消耗很大。缺页中断分散在整个请求的处理过程中,所以表现为分配语句耗时(10us)相对于整条请求的处理时间(1000us)比重很小。

解决办法
将动态内存改为静态分配,或者启动的时候,用malloc为每个线程分配,然后保存在threaddata里面。但是,由于这个模块的特殊性,静态分配,或者启动时候分配都不可行。另外,Linux下默认栈的大小限制是10M,如果在栈上分配几M的内存,有风险。  
禁止malloc调用mmap分配内存,禁止内存紧缩。
在进程启动时候,加入以下两行代码:
mallopt(M_MMAP_MAX, 0); // 禁止malloc调用mmap分配内存
mallopt(M_TRIM_THRESHOLD, -1); // 禁止内存紧缩
效果:加入这两行代码以后,用ps命令观察,压力稳定以后,majlt和minflt都为0。进程的系统态cpu从20降到10。

小结
可以用命令ps -o majflt minflt -C program来查看进程的majflt, minflt的值,这两个值都是累加值,从进程启动开始累加。在对高性能要求的程序做压力测试的时候,我们可以多关注一下这两个值。  
如果一个进程使用了mmap将很大的数据文件映射到进程的虚拟地址空间,我们需要重点关注majflt的值,因为相比minflt,majflt对于性能的损害是致命的,随机读一次磁盘的耗时数量级在几个毫秒,而minflt只有在大量的时候才会对性能产生影响。
C代码时间复杂度分析与优化实践指南 在编程竞赛和实际软件开发中,高效的C代码往往能决定程序的成败。本文将全面介绍C代码的时间复杂度分析方法,并提供一系列实用的优化技巧,帮助开发者编写出性能更优的程序。 阅读详情

相关推荐

8051到C251代码移植优化与内存寻址差异解析

在嵌入式系统开发中,内存寻址是影响代码效率和性能的关键因素。8051架构采用分区的内存空间设计,而C251架构则引入了统一的线性地址空间,这种差异导致直接移植代码时可能出现体积膨胀问题。通过理解两种架构的内存模型差异,开发者可以实施有效的代码优化策略,如使用头文件转换技术和变量类型优化。这些方法不仅能减少代码体积,还能提升执行效率,特别适用于工业控制等对性能要求严格的场景。内存寻址优化和代码移植是嵌入式开发中的常见挑战,掌握这些技巧有助于实现平滑的架构升级。

weixin_30644369的博客 384

不显示删除回复显示所有回复显示星级回复显示得分回复 [推荐] [百度分享]频繁分配释放内存导致的性能问题的分析

现象1 压力测试过程中,发现被测对象性能不够理想,具体表现为: 进程的系统态CPU消耗20,用户态CPU消耗10,系统idle大约70 2 用ps -o majflt,minflt -C program命令查看,发现majflt每秒增量为0,而minflt每秒增量大于10000。初步分析majflt代表major fault,中文名叫大错误,minflt代表minor fault,中文名叫小错误。

newish21的专栏 712

C/C++编译器内存优化技术:内存优化关注程序对内存的访问和使用,以提高内存访问速度和减少内存占用。

C/C++编译器内存优化技术:内存优化关注程序对内存的访问和使用,以提高内存访问速度和减少内存占用。

探索C++编程的奥秘,分享深入的技术见解和实践,旨在激发读者创造力与解决问题的思维。 3423

Linux 服务器的那些性能参数指标

一个基于 Linux 操作系统的服务器运行的同时,也会表征出各种各样参数信息。通常来说运维人员、系统管理员会对这些数据会极为敏感,但是这些参数对于开发者来说也十分重要,尤其当你的程序非正常工作的时候,这些蛛丝马迹往往会帮助快速定位跟踪问题。 这里只是一些简单的工具查看系统的相关参数,当然很多工具也是通过分析加工 /proc、/sys 下的数据来工作的,而那些更加细致、专业的性能监测和

java的平凡之路 1286

手把手配置:用Synopsys VDK为英飞凌TC4x系列MCU做虚拟原型开发

本文详细介绍了如何使用Synopsys VDK为英飞凌TC4x系列MCU进行虚拟原型开发,涵盖开发环境搭建、关键外设虚拟化配置、AUTOSAR栈集成及虚拟调试与性能调优全流程。通过虚拟原型技术,开发者可提前6-12个月启动软件开发,显著提升汽车电子项目的开发效率。

weixin_30606461的博客 290

网工实验笔记:SNMP的配置

简单网络管理协议SNMP(Simple Network Management Protocol)是广泛应用于TCP/IP网络的网络管理标准协议。SNMP提供了一种通过运行网络管理软件的中心计算机(即网络管理工作站)来管理设备的方法。

2301_76170756的博客 2116

linux malloc内存申请相关参数设置

情况一、malloc小于128k的内存 malloc小于128k的内存时使用brk分配内存,将_edata往高地址推(只分配虚拟空间,不对应物理内存(因此没有初始化),第一次读/写数据时,引起内核缺页中断,内核才分配对应的物理内存,然后虚拟地址空间建立映射关系),如下图: 1、进程启动的时候,其(虚拟)内存空间的初始布局如图1所示。 其中,mmap内存映射文件是在堆和栈的中间(例如libc-2.2...

sun172270102的博客 4079

调节桌面图标大小的方法(编程)

如果你对其他操作系统或编程语言有类似的需求,可以根据具体的情况进行相应的调整和搜索相关的库和方法。在编程中,我们可以使用各种桌面应用程序来调节桌面图标的大小。库提供的函数,我们获取了桌面图标的窗口句柄,并使用Windows消息发送方式设置图标的大小。你可以根据自己的需求修改代码中的图标大小值,并在运行代码后观察桌面图标的变化。函数并传入所需的图标大小,这里设置为48x48像素。首先,我们需要使用Python的第三现的方法。首先,我们需要使用Python的第三方库。首先,我们需要使用实现的方法。

CyberFlare的博客 439

进程分配内存的两种方式--brk() 和mmap()(不设计共享内存)

如何查看进程发生缺页中断的次数?          用ps -o majflt,minflt -C program命令查看。           majflt代表major fault,中文名叫大错误,minflt代表minor fault,中文名叫小错误。           这两个数值表示一个进程自启动以来所发生的缺页中断的次数。 发成缺页中断后,执行了那些操作?

鱼思故渊的专栏 1万+

手机直连低轨卫星通信:架构、关键技术和未来展望

【摘 要】借助低轨卫星星座全时全域覆盖优势,手机直连卫星通信预期成为6G重要特征之一。首先介绍了手机直连卫星的测试验证、标准化与商业项目发展现状。其次,介绍了基于透明转发、部分可再生处理、完全可再生处理、集成接入和回传的四种手机直连低轨卫星网络架构及组网方式。通过分析手机直连低轨卫星网络场景下高移动性与大传输时延等带来的接入与传输问题,提出对地面移动通信体制进行适应性改进的关键技术方案。最后,探讨了未来手机直连低轨卫星发展发向和潜在思路。通过上述阐述与分析,提供未来发展手机直连低轨卫星通信的可行路径。【关

fzq0625的博客 1707

【Python百日进阶-Web开发-Feffery】Day385 -“一起Dash”训练营Lesson-07_利用fac构建表单(上)

文章目录前言:fac是什么?“人生苦短,我用Python;Web开发,首选Feffery!”↓↓↓ 今日笔记 ↓↓↓一、费老师课堂1.1 什么是表单1.2 页面效果1.3 课堂源码二、课后作业2.1 页面效果2.2 项目源码 前言:fac是什么? feffery-antd-components(简称fac),是国内大佬费弗里(Feffery)老师基于著名的React UI组件库ant design进行二次开发,将ant design中的诸多实用组件及特性引入Dash,帮助开发者使用极低的纯Python代

专注于医院数据分析技术与系统开发的创作与分享。 251

18. C语言 结构体内存布局分析与优化

C语言中的结构体内存布局是一个复杂但重要的概念。理解结构体的内存对齐与填充规则,有助于我们在开发过程中有效地优化内存使用。通过合理调整结构体成员的顺序,或者在某些情况下使用编译器指令,可以减少内存的浪费,提高程序的性能和效率。希望通过本文的分析,能够帮助读者更好地理解和掌握结构体的内存布局与优化技巧。

涛ing的博客 1614

uniapp - 如何跟内嵌 web-view 组件内的网页交互,与 web-view 内嵌网页进行双向通信(uniapp 与 webview 网页之间的 “相互“ 传值)提供详细的示例代码及解决方案

uni-app如何实现在H5环境中与web-view中的网页交互通讯uniappuni-app 与 web-view内嵌网页 双向通信 如何跟内嵌web-view交互uniappAPP与webview子页面交互uniappAPP与webview子页面交互关于uni-app 使用 web-view 页面之间互相跳转、通信等问题uniapp的web-view嵌入网页,网页与uniapp通信webview如何与uniapp写的H5页面交互嵌套webview调用uniapp各种API组件实现H5和app通讯和交互

✅ 精选推荐文章 1万+

C语言内存优化——继续含泪总结

之前分析了基本数据类型的优化,现在开始涉及全局和局部变量的优化,话说这个东西我从没想过还能这样优化的喂!全局变量 / Global variables全局变量不会被分配在寄存器上,修改全局变量需要通过指针或者调用函数的方式间接进行。所以编译器不会将全局变量存储在寄存器中,那样会带来额外的、不必要的负担和存储空间。所以在比较关键的循环中,我们要不使用全局变量。如果一个函数要频繁的使用全局变量,我们可...

sinat_36098122的博客 5069

MIL图像处理那些事:MIL的安装和MIL工具箱

MIL图像处理那些事:MIL的安装和测试,如何用C#使用MIL

十多年IT经验,专注机器视觉,智能制造半导体行业 5273

【知识图谱】neo4j安装与配置_社区版_2025(附完整安装软件包)

(经历过各种版本NEO4J,遇见杂七杂八的各种问题,也看过非常多很好的教程,特此来分享一下,为大家排排坑。

知识靠谱的博客 2万+

Go内存逃逸分析:优化堆内存分配详解

Go语言的内存分配模型结合了编译期的静态分析和运行时的动态管理。尽可能在栈上分配,必要时才使用堆内存。mspan:最基本的内存管理单元mcache:每个P(处理器)的本地缓存mcentral:全局内存缓存这种分层设计最大限度减少了并发场景下的锁竞争,为Go的高性能并发提供了基础保障。简单来说,内存逃逸是指原本应该在栈上分配的变量,因为某些原因不得不在堆上分配的现象。就像一个本该在家吃饭的人,因为各种原因不得不去餐厅用餐一样。

sinat_27016095的博客 1044

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

代码中的内存使用模式分析与优化策略

内存使用模式的优化是提高程序性能的关键因素之一。通过选择合适的数据格式、优化数据结构、改善内存访问模式以及合理管理资源,可以显著提高内存的使用效率,降低带宽需求,从而提升整体性能。在实际开发中,建议定期使用性能分析工具来监测内存使用情况,识别潜在的瓶颈,并根据分析结果进行针对性的优化。随着RAM成本的下降,内存分析对很多业务都变得可行,合理利用内存可以为应用程序带来显著的性能提升。记住,优化内存使用不仅是为了提高性能,也是为了提高程序的可扩展性和可维护性。

jie_kou的博客 984

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

llama2.c批处理优化:批量推理的内存与计算优化

在实际部署场景中,我们经常需要对大量文本进行批量推理处理。传统的单次推理模式存在以下问题: - **内存碎片化**:每次推理都需要重新分配和释放内存 - **计算资源浪费**:无法充分利用现代CPU的并行计算能力 - **上下文切换开销**:频繁的模型加载/卸载导致额外开销 - **缓存不友好**:数据局部性差,缓存命中率低 ## 批处理优化的核心思路 ### 内存管理优化 llama...

gitblog_00134的博客 818

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

C优化篇之优化内存访问

目前CPU运行速度远超过内存访问速度,且从趋势看这种速度差距还会越拉越大,提高内存访问效率将是软件优化重要而长期的课题。内存访问优化的一般性措施可大体分两方面:1)减少内存访问;2)调整代码使程序集中顺序地访问内存。 一、减少内存访问的措施包括: a.充分利用寄存器     充分利用寄存器缓存数据,是减少内存访问的思路之一。C程序编译后哪些元素由寄存器存储,哪些又会放进内存,取决于CPU以及

半山茶馆 7050

【C++】深入理解C语言中的特殊字符处理与问题分析优化

在C语言编程过程中,格式化输出函数printf是一个高频使用的工具。然而,由于其支持格式化字符串,某些特殊字符(如%)的输出和处理经常导致困惑。本文通过具体问题的剖析,包括在洛谷平台的编程题目和相关代码的优化实践,系统地讲解了printf中特殊字符处理的机制、常见错误的排查方法,以及代码优化的技巧。希望通过这一篇文章,读者能对C语言的printf机制和编程逻辑有更深刻的理解。 2025.1.3-✍56min

禅宗里有一个词叫做“因缘和合”。 所谓因缘,是指事件要发生所必须的条件。因缘和合就是当你聚集了这件事的一切条件,它就会自然而然的发生。“它就会自然而然的发生”,这种朴素而坚定的价值观让我们感到无比安心,安心到可以不用有任何担心焦虑。 1536

Cppcheck内存占用优化:大型项目分析的资源管理指南

在处理百万行级C/C++代码时,Cppcheck静态分析工具常面临内存溢出和分析超时问题。本文系统梳理了内存占用的关键影响因素,提供从编译配置、分析参数到代码重构的全链路优化方案,使原本需要32GB内存的项目能在8GB环境下完成分析,平均内存占用降低62%,分析效率提升40%。 ## 内存占用痛点分析 ### 典型场景问题 大型项目分析中常见以下内存瓶颈: | 场景 | 内存占用特征 | ...

gitblog_00555的博客 1039

探索编程万象Java、Python与C系语言(C/C#/C++)的特性对比与实战选择

本文通过对比Java、Python和C系语言(C/C++/C#)的特性差异,提供多维度的决策分析框架。处理10万条记录的ETL任务,Pandas实现较纯C++版慢约3倍,但开发效率高3-5倍,适合迭代式开发。JIT编译器将热点代码编译为本地机器码,在长期运行的服务端应用(如电商交易系统)中,吞吐量可达到C的85%-90%。Spark引擎采用Scala/Java实现核心组件保证分布式稳定性,Python用于流式计算的快速迭代,C++处理具体算法的性能瓶颈环节(如图计算引擎GraphX)。

YIBpihDa的博客 642

如何用Memray优化GB级Python应用:内存分析的终极指南

Memray是一款强大的Python内存分析工具,专为解决大内存应用的性能问题而设计。无论是处理GB级数据的科学计算项目,还是需要长时间运行的服务端应用,Memray都能帮助开发者精准定位内存泄漏、优化内存使用,提升应用稳定性和效率。本文将带你全面掌握Memray的核心功能和实战技巧,让你轻松应对大内存应用的优化挑战。 ## 📊 为什么选择Memray?大内存应用的痛点与解决方案 在处理大规

gitblog_00185的博客 686

Android 内存分析

内存性能分析器是 Android Profiler 中的一个组件,可帮助识别可能会导致应用卡顿、冻结甚至崩溃的内存泄漏和内存抖动。它显示一个应用内存使用量的实时图表,可以捕获堆转储、强制执行垃圾回收以及跟踪内存分配。或者,可以从命令行使用 dumpsys检查应用内存,还可以在 logcat 中查看 GC 事件。

weixin_75102992的博客 2242

C代码性能优化策略

需要注意的是,这些微观优化应该基于性能分析数据有针对性地进行,并且需要进行严格的测试,因为有些优化可能会损害代码的可读性和可维护性。通过剖析工具,开发者能够将优化精力集中在最耗时的循环、频繁调用的函数或效率低下的算法上,从而避免无谓的优化,实现精准打击。然而,需要注意的是,高级别优化可能会增加编译时间,或在极少数情况下改变程序行为,因此需要在性能提升与稳定性之间找到平衡点。对于需要频繁创建和销毁的小对象,使用内存池技术可以显著提高性能,即预先分配一大块内存,然后自行管理其中的分配和回收。

xyj4189的博客 586
上一篇: 在 UltraEdit 中安装jlint 对javascript做语法检查
下一篇: 【转】 linux fork()详解
stund
博客等级 码龄18年 28粉丝 15原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值