一次内存紧缩

数据结构的存储紧缩 在整个动态存储管理过程中,不管哪个时刻,可利用空间都是一个地址连续的存储区﹐在编译程序中称之为“堆”,每次分配都是从这个可利用空间中划出一块。其实现办法是:设立一个指针,称之为堆指针﹐始终指向堆的最低(或最高)地址。当用户申请N个单位的存储块时,堆指针向高地址(或低地址)移动N个存储单位,而移动之前的堆指针的值就是分配给用户的占用块的初始地址。回顾第4章中提及的串值存储空间的动态分配就是用的这种堆的存储管理。例如,某个串处理系统中有A,B,C,D这4个串,其串值长度分别为12,6、10和8。... 阅读详情

在linux系统下,一块内存被C的free函数或者C++的delete函数显式释放后,释放掉的内存不一定马上交还给系统。简单地说,系统通过动态分配给进程的内存分为两部分: mmap和brk. mmap在进程的虚拟地址空间中找出一块空闲区域分配给进程,释放后马上归还给系统; brk在进程数据段内找到一块空闲区域给系统,是通过push _edata栈顶指针实现。两种情况下都不会直接分配物理内存,只有在访问虚拟空间地址产生缺页中断的时候才会建立虚拟地址与内存地址间的映射。brk分配的内存在被释放后,如果堆栈高地址的内存块没有释放,那么低地址内存块就算被free也不会归还给系统。这就是明明被显式free掉的内存仍然不在系统空闲内存列表中,而进程什么内存泄露都查不出来的原因。

解决DVP内存使用上涨的方法是强制系统在free掉图片buffer后将堆栈栈顶的内存区域强制归还给系统(称为一次内存紧缩)。为此,在代码内, free掉FRameBufMng后调用malloc_trim(0)即可。问题由此解决。

现象
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(可由M_TRIM_THRESHOLD选项调节)时,执行内存紧缩操作(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只有在大量的时候才会对性能产生影响

读书笔记之《数据结构》---第八章 动态存储管理 本章目录 1.概述 2.可利用空间表及分配方法 3.边界表示法 4.伙伴系统 5.无用单元收集 6.存储紧缩 概述 动态存储管理的基本问题是系统如何应用户提出的“请求”分配内存。 可利用空间表及分配方法 可利用空间表可以有下列3中不同的结构形式: 1.系统运行期间所有用户请求分配的存储量大小相同,分配固定大小的控件给用户 2.系统运行期间用户请求分配的存储量有若干大小的规格 3.系统运行期间分配给... 阅读详情

相关推荐

基于Isaac Gym与PPO算法的机械臂抓取任务仿真与强化学习实战(附完整代码与训练策略)

本文详细介绍了基于Isaac Gym与PPO算法的机械臂抓取任务仿真与强化学习实战。通过环境搭建、PPO算法实现、奖励函数设计等核心环节的优化,结合完整代码与训练策略,显著提升机械臂抓取效率与成功率。特别适合开发者快速掌握强化学习在机器人控制领域的应用。

weixin_29256771的博客 598

操作系统原理,物理内存“扩充”技术,内存紧缩,覆盖,交换,虚拟内存思想

当内存空间不足以存放下进程是,需要使用到内存“扩充”技术,但不是真的扩充了内存。 一、内存“扩充”技术 1、内存紧缩技术:在可变分区型的操作系统中调节进程在内存中的位置,将进程间的外碎片合成为可用的内存空间并利用。 2、覆盖技术overlaying 2、交换技术swapping 4、虚拟内存技术virtual memory二、覆盖技术(早期操作系统) 1、应对问题:程序大小超过了物理内存总和 2、解决方案:程序的不同部分在内存中共享一块区域并相互覆盖 2.1、操作系统按照程序自身的逻...

ganfanren00001的博客 3910

飞思卡尔16位单片机(二)——CodeWarrior开发环境搭建及新建、调试工程

一、安装CodeWarrior 飞思卡尔16位单片机的开发环境为CodeWarrior5.1,这个软件安装比较简单,软件的安装文件可以从相应的网站上下载。安装CodeWarrior所需要的电脑的硬件资源也比较宽泛,目前一般的电脑都可以满足这个要求,可以支持win10、win7等操作系统。安装过程按照按照软件的提示一步步操作即可。 二、安装USBDM驱动 USBDM是...

bigmarshal的博客 1万+

linux 内存紧缩,一文浅析内存管理机制

原标题:一文浅析内存管理机制“本文主要介绍内存管理机制:物理内存与虚拟内存的关系,Linux内存管理机制,Python内存管理机制,Nginx内存管理机制,环形缓冲区机制,以及TC-malloc内存分配器的Andriod管理机制的简单介绍。”一. 物理内存与虚拟内存众所周知,程序需要加载到 物理内存才能运行, 多核时代会出现多个进程同时操作同一物理地址的情况,进而造成混乱和 程序崩溃。计算机当中很...

weixin_34252946的博客 546

10分钟快速搭建OpenClaw(基于Windows+飞书)

OpenClaw 是一款功能强大的 AI 智能体工具,能够帮助用户管理邮件、日历等日常事务。本文详细介绍了在 Windows11 系统上安装和配置 OpenClaw 的完整步骤,包括 Node.js 环境搭建、Git 安装、OpenClaw 部署以及飞书机器人创建与对接。通过简单的命令行操作和可视化界面配置,用户可以快速完成 AI 助手部署,实现智能办公自动化。文中还提供了飞书机器人权限设置等关键环节的图文指引,帮助用户轻松完成系统集成。

Hello, New World! 2923

Origin画图——获取论文图中数据

有时候需要已发表论文的图的数据,这里使用Origin软件取值,并且可以实现对图形再次画图。 Step 1. 打开origin软件,点击工具,图形数字化工具。 Step 2. 打开要获取数据的图片。拉动红蓝坐标,与图的坐标轴所贴合。 Step 3. 打开要获取数据的图片。拉动红蓝坐标,与图的坐标轴所贴合。 Step 3. 设置参数横轴起始坐标为300-900,纵轴为1.8-2.6. Step 4. 点击第五个手动取点,取出图中数据点。 Step 5. 依次对原图进行取点。点击项目资源查看图。

qq_42278015的博客 5181

linux 内存紧缩,避免物理内存碎片化 - 内存紧缩

长期存在的内存碎片问题,已经有多篇文章提及了。简单的说:当系统运行一段时间后,空闲页面趋向于散落在不连续的空间,很难再有足够长的连续物理内存页面分配。内核开发者已经下了很多工夫,减少大块连续物理内存的分配,因此大部分内核功能并不会受到页面碎片化的影响。但是仍然存在对大块连续物理内存的需要,在内存碎片化系统上的内存分配,因此可能失败。过去几年,内核开发者们做出了各种努力来解决这个问题,导致了了ZON...

weixin_34379989的博客 656

国密SSL实战:手把手教你用Wireshark抓包分析GMTLS协议(附证书链验证技巧)

本文提供了一份国密SSL(GMTLS)协议的实战抓包分析指南。通过详细讲解Wireshark的配置、GMTLS握手流程的捕获与筛选,以及双证书机制和证书链的深度解析,帮助工程师和开发人员掌握使用Wireshark排查国密SSL连接问题、进行密评和协议调试的核心技巧。

rgv234567的博客 501

linux 内存紧缩,内存紧缩(内存碎片化处理)

前边介绍的有关动态内存管理的方法,无论是边界标识法还是伙伴系统,但是以将空闲的存储空间链接成一个链表,即可利用空间表,对存储空间进行分配和回收。本节介绍另外一种动态内存管理的方法,使用这种方式在整个内存管理过程中,不管哪个时间段,所有未被占用的空间都是地址连续的存储区。这些地址连续的未被占用的存储区在编译程序中称为堆。图 1 存储区状态假设存储区的初始状态如图 1 所示,若采用本节介绍的方法管理这...

weixin_31081677的博客 883

深入浅出:大型语言模型(LLM)的全面解读

在当今的数字化时代,人工智能技术已经成为各行各业的核心驱动力之一。而在人工智能的领域中,大型语言模型(LLM)作为一种引人瞩目的技术,正在以其强大的语言理解和生成能力引领着一场革命。本文旨在深入浅出地解读大型语言模型,探讨其背后的原理、技术突破、应用场景以及未来发展趋势。

fudaihb的博客 10万+

c语言实现求一个矩阵特征值和特征向量

前言 求矩阵的特征值,主要是用的QR分解,在我的有一次博客里,我已经详细地给出了计算的过程,大家有兴趣可以去看下,经过几天的钻研,终于完成了整个的eig算法。下面我将把我的整个代码附上,有不懂的可以问我,欢迎一起讨论学习! 这是对上一次的修改版,上一次写的程序是在C++编译环境下编译的,所以放在c里面编译有些会出错。 最后,如果有不对的地方希望大...

qq_36417014的博客 2万+

已修改内存占用高_内存紧缩(内存碎片化处理)

前边介绍的有关动态内存管理的方法,无论是边界标识法还是伙伴系统,但是以将空闲的存储空间链接成一个链表,即可利用空间表,对存储空间进行分配和回收。本节介绍另外一种动态内存管理的方法,使用这种方式在整个内存管理过程中,不管哪个时间段,所有未被占用的空间都是地址连续的存储区。这些地址连续的未被占用的存储区在编译程序中称为堆。图 1 存储区状态假设存储区的初始状态如图 1 所示,若采用本节介绍的...

weixin_39926943的博客 1211

Android 13.0 双屏时触摸失效问题排查与修复

摘要:本文记录了RK3588 Android12开发板上主屏触摸失效问题的排查与解决过程。通过分析发现,USB触摸设备被错误关联到辅屏(displayId=3)而非主屏(displayId=0)。解决方案是修改TouchInputMapper.cpp,强制触摸设备使用INTERNAL viewport(主屏),并保持设备在viewport不活跃时仍启用。该修改涉及约40行代码,有效解决了多显示器环境下触摸设备错误映射的问题,同时提供了详细的调试方法和注意事项。

ip0417的博客 352

【C 数据结构-动态内存管理】5. 内存紧缩(内存碎片化处理)

文章目录【 1. 堆 】【 2. 分配算法 】【 3. 回收算法 】 【 1. 堆 】 无论是边界标识法还是伙伴系统,都是将空闲的存储空间链接成一个链表,即可利用空间表,对存储空间进行分配和回收。本节介绍另外一种动态内存管理的方法,使用这种方式在整个内存管理过程中,不管哪个时间段,所有未被占用的空间都是地址连续的存储区,这些 地址连续的未被占用的存储区 在编译程序中称为 堆。 假设存储区的初始状态如上图所示,若采用本节介绍的方法管理这块存储区,当 B 占用块运行完成同时所占的存储空间释放后,存储区的状

普罗米修斯的博客 762

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

避免物理内存碎片化 - 内存紧缩

原文地址 http://lwn.net/Articles/368869/ 长期存在的内存碎片问题,已经有多篇文章提及了。简单的说:当系统运行一段时间后,空闲页面趋向于散落在不连续的空间,很难再有足够长的连续物理内存页面分配。内核开发者已经下了很多工夫,减少大块连续物理内存的分配,因此大部分内核功能并不会受到页面碎片化的影响。但是仍然存在对大块连续物理内存的需要,在内存碎片化系统上的内存分

kickxxx的专栏 6118

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

【原创】HBase的分裂(Split)与紧缩(Compaction)

Hbase的紧缩与分裂 Hbase的紧缩与分裂过程是对数据管理中必不可少的功能,正是因为它们的存在为Hbase拥有高效读写性能及集群的负载均衡提供了保证,接下来对这两个过程作一下详细的介绍。 Region概述 Hbase的紧缩与分裂的发生都在在Region中进行的,了解过Hbase的伙伴应该不会陌生,这里再对Region的结构功能作一个简单介绍。Region是 HBase中分布式存储和负载均衡的最...

weixin_42162155的博客 5117

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

【Godot4.2】GDScript数组分类及类型化数组和紧缩数组概述

GDScript的数组是一种很常用的数据类型。本文主要阐述一下GDScript数组分类,以及官方文档和大多数视频或教程较少提及的类型化数组和紧缩数组。

巽的博客 2895

内核如何管理内存碎片?

内核管理内存碎片的过程涉及多个机制和策略,以确保物理内存能够高效利用,并减少内存碎片对系统性能的影响。和。

运维老生常谈 943

【操作系统】Linux程序内存结构&内存分配

@TOC【操作系统】Linux程序内存结构&内存分配 【操作系统】Linux程序内存结构&内存分配 对于一个32位的linux操作系统,他的进程内存分布如下图: 低地址从0x00000000开始 高地址到0xFFFFFFFF 代码区: 存放程序执行代码的一段内存,内存区域只读,并且在代码段中可能也包含一些只读常量。 数据区 分为已初始化数据区 (.data)和未初始化数据区(BSS),分别用来存放已经初始化的全局变量和静态变量和未初始化的全局变量和静态变量。 其中BSS不占据目标文

netlogs的博客 1592

malloc原理和内存分配

当一个进程发生缺页中断的时候,进程会陷入内核态,执行以下操作:1、检查要访问的虚拟地址是否合法 2、查找/分配一个物理页 3、填充物理页内容(读取磁盘,或者直接置0,或者啥也不干) 4、建立映射关系(虚拟地址到物理地址) 重新执行发生缺页中断的那条指令 如果第3步,需要读取磁盘,那么这次缺页中断就是majflt,否则就是minflt。内存分配的原理从操作系统角度来看,进程分配内存有...

zpznba的博客 1488

系统内存管理介绍,内存申请及回收流程

使用伙伴系统进行存储空间的管理过程中,在用户申请空间时,由于大小不同的空闲块处于不同的链表中,所以分配完成的速度会更快,算法相对简单。回收存储空间时,对于空闲块的合并,不是取决于该空闲块的相邻位置的块的状态;而是完全取决于其伙伴块。所以即使其相邻位置的存储块时空闲块,但是由于两者不是伙伴的关系,所以也不会合并。这也就是该系统的缺点之一:由于在合并时只考虑伙伴,所以容易产生存储的碎片。无用单元的收集可以采用以上 3 中算法中任何一种。

Aiky哇 1184

进程分配内存的两种方式—brk()和mmap()

内存分配的原理 从操作系统角度来看,进程分配内存有两种方式,分别由两个系统调用完成:brk()和mmap() 1.brk是将数据段的最高地址指针_edata往高地址推; 2.mmap是在进程的虚拟地址空间中(堆和栈中间,文件映射区)找一块空闲的虚拟内存。这两种方式分配的都是虚拟内存,没有分配物理内存。在第一次访问已分配的虚拟地址空间的时候,发生缺页中断,操作系统负责分配物理内存,然后建立虚拟内存和...

弯弯传奇的博客 2300

操作系统学习笔记(十七)~内存管理背景+连续内存分配

8.1 内存管理背景 1、把作业地址空间中使用的逻辑地址变成内存中物理地址称为()B A.加载 B.重定位 C.物理化 D.逻辑化 解释: 2、静态重定位的时机是()C A.程序编译时 B.程序链接时 C.程序装入时 D.程序运行时 3、能够装入内存任何位置的代码程序必须是()C A.可动态链接的 B.可定位的 C.可动态绑定的 D.可静态链接的 4、动态重定位过程依赖于( )。A、B、C A.可...

海到无边天作岸 山登绝顶我为峰 2380

内存碎片化

内存碎片化(Memory Fragmentation)是指内存中存在一些不连续的、未被充分利用的小块空闲内存,这些小块内存虽然总量可能足够,但由于它们分散在内存中,无法被有效利用,从而导致整体内存利用效率降低的现象。总的来说,内存碎片化是一个常见的内存管理问题,需要采取合适的策略和方法来减轻其影响,提高系统的内存利用效率。

大黄鸭在发光的专栏 1344

频繁分配释放内存导致的性能问题的分析

刚才看了百度同学的分享,觉得挺有意思。试着总结一下:征兆:1. system cpu占用率偏高。2. 执行命令 用ps -o majflt,minflt -C program命令查看,majflt或者minflt每秒增量很大。原因:频繁的分配释放内存,导致缺页中断次数很高。而缺页中断的处理是由系统在内核态完成的,所以system cpu利用率偏高,导致性能问题的产生。解决办法:将动态内存改为静态分配,或者启动的时候,用malloc为每个线程分配,然后保存在threaddata里面。但是,由于这个模块的特殊性

redgrass的专栏 1093

数据结构之动态内存管理机制

使用伙伴系统进行存储空间的管理过程中,在用户申请空间时,由于大小不同的空闲块处于不同的链表中,所以分配完成的速度会更快,算法相对简单。回收存储空间时,对于空闲块的合并,不是取决于该空闲块的相邻位置的块的状态;而是完全取决于其伙伴块。所以即使其相邻位置的存储块时空闲块,但是由于两者不是伙伴的关系,所以也不会合并。由于在合并时只考虑伙伴,所以容易产生存储的碎片。无用单元的收集可以采用以上 3 中算法中任何一种。

ZhangJiqun&191cm&85kg 1359
上一篇: Linux平台的ASLR机制
下一篇: C++实现回调函数的几种方式
evilcode
博客等级 码龄20年 307粉丝 16原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值