Linux中maps/smaps的妙用_smaps maps-程序员宅基地

技术标签: C++  内存分配  android  linux  Perl  嵌入式  

这篇文章的目的是为了记录之前做过的一个工作:减小server运行时所占的内存。

这个server本来是一个PC上的多媒体server,后来我们把它移植到android机顶盒上,仍然当一个server使用,但是用户量比之前小很多。

原来的server对内存的使用也没有什么顾虑,一般都配备很大的内存,而机顶盒对内存占用要求比较高,因为它本身的内存就很小,还有其他的程序在运行,所以我们就面临着减少server所占用的内存的问题。

也许你会问,这个问题不是很简单吗,干嘛还要拿来长篇大论。

你说的对,这个问题现在看来确实不算大事。只是项目一开始的时候大家比较关注功能的实现,到了后来才觉得有必要把内存占用给减小。

刚拿到这个问题,你会怎么分析呢。看代码???代码太多了,而且是很久很久以前的代码,没有几个人对它很熟悉。

先在网上搜了一下,发现了一本书《嵌入式linux内存与性能详解》,这本书严格来讲是一些工作经验的总结,很感谢作者的无私,所以作者也是我将学习的对象,要和大家分享。

这本书中提到了很多嵌入式上的内存和性能上的优化方法,对我很有启发。

我一开始尝试在malloc和free上加钩子(hook),类似于android bionic里的里面采用的方法,我不是怀疑原来的server有严重的内存泄漏(因为这个server已经跑了很多年了),而是怀疑哪个地方有很大的内存分配。但是不幸的是用加钩子的方法并没看出哪个地方有大内存分配。


内存不是new/malloc出来的,那是哪来的呢?


于是被迫看代码,发现程序中创建了很多线程,每个线程会通过mmap来设置线程栈和信号栈(sigaltstack)。把它们屏蔽掉之后,系统就会默认分配相应的栈给每个线程使用,但是效果不明显,内存占用还是很大。我们知道mmap可以分配很大的内存区域。于是我grep mmap,发现就只有线程栈和线程信号栈用到了mmap。 

不过程序中创建的这些匿名内存在地址空间中的具体位置引起了我的兴趣。我们很多时候能只关注进程的虚拟地址空间分布,知道线程的堆是进程范围内共享的,却很少关注线程的栈是如何管理的。 于是查看maps,看到他们是占用了不同于栈的区域,有点类似于动态库的位置(其实动态库通常也是用mmap来加载的)。 

这时我才开始计算每个区域的实际大小。 终于有了重大发现,好几个很大的区域都是匿名的,但又不是通过mmap分配的。 

于是我采用最原始的办法来定位这个内存是由谁分配的。通过在程序中加上dump maps和smaps的方法来不断缩小范围。

dump maps的方法很简单,将/proc/self/maps文件copy到你指定的文件,smaps类似。

然后对比这些maps,看看是在哪个地方之后,这些匿名的内存区域被分配了。


这个原始的办法很奏效,很快就定位到有一个源文件中在分配epoll相关的数据结构时,用的是new,但申请的size很大,有1920k之多,这么大的内存分配,是不会走brk(malloc的底层)的,而是用mmap来分配。所以在maps中才会有那些匿名的区域。

分析一下原因,原来的server的用户访问量很大,而内存通常也配备充足,所以就分配了很大的内存来处理异步事件。

而将server移植到机顶盒之后,目标用户访问量不会太多,即使用浏览器访问,浏览器开的多线程也不会太多,所以将上面申请的size减小到一个合理的值之后,server所占用的内存大幅减小。


看似很简单的一件事情(现在看来确实也不复杂),但是却能起到很好的效果。

所以C/C++的开发,对于底层的理解必须得深,深了后很多事情就是顺理成章的,很简单的了。

这方面的书籍个人比较喜欢的有:《程序员的自我修养》,《深入理解计算机系统》,《深度探索C++对象模型》,其实上面提到的《嵌入式linux内存与性能详解》也绝对值得一看。


另外多说一句,smaps里面的信息比maps要全,更详细一些,它会将每个动态库所占的内存分成共享的,私有的等。

为了看出某个动态库真正占用了多少内存,我们需要解析smaps里面的各个字段,网上有一个perl脚本smem.pl可以分析smaps文件,该脚本用到了cpan包:Linux::Smaps。


版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/hp_truth/article/details/45029291

智能推荐

浅谈UDP(数据包长度,收包能力,丢包及进程结构选择)-程序员宅基地

文章浏览阅读210次。UDP数据包长度UDP数据包的理论长度udp数据包的理论长度是多少,合适的udp数据包应该是多少呢?从TCP-IP详解卷一第11章的udp数据包的包头可以看出,udp的最大包长度是2^16-1的个字节。由于udp包头占8个字节,而在ip层进行封装后的ip包头占去20字节,所以这个是udp数据包的最大理论长度是2^16-1-8-20=65507。然而这个只是udp数据包的最大理论长度。首..._udp接收数据 客户端处理时间太长

计算机毕业设计springboot基于JAVA的房产销售管理系统tf4839【附源码+数据库+部署+LW】-程序员宅基地

文章浏览阅读123次。选题背景:房地产行业一直是国民经济的重要支柱之一,对于城市发展和居民生活质量有着重要影响。为了提高房地产销售管理的效率和精度,基于JAVA的房产销售管理系统的设计与实现具有重要的背景意义。通过建立一个全面、高效的房产销售管理系统,可以帮助房地产企业更好地管理销售流程、优化资源配置,提升销售业绩和客户满意度。选题意义:首先,基于JAVA的房产销售管理系统可以提高销售流程的效率和精度。传统的房地产销售过程中,涉及到大量的信息记录、数据分析和报表生成等工作,需要耗费大量的人力和时间。而通过房产销售管理系统

3.3 SPI串行Flash配置模式-程序员宅基地

文章浏览阅读757次。SPI串行Flash配置模式1.SPI串行配置介绍串行Flash的特点是占用管脚比较少,作为系统的数据存贮非常合适,一般都是采用串行外设接口(SPI 总线接口)。Flash 存贮器与EEPROM根本不同的特征就是EEPROM可以按字节进行数据的改写,而Flash只能先擦除一个区间,然后改写其内容。一般情况下,这个擦除区间叫做扇区(Sector),也有部分..._外挂spi flash

monogame Unable to load DLL 'openal32.dll': The specified module could not be found_load openal32-程序员宅基地

文章浏览阅读2.5k次。monogame 新建一个项目,运行报错 Unable to load DLL 'openal32.dll': The specified module could not be found解决方法游戏需要安装下列运行库Game For Windows Live 3.0http://download.microsoft.com/download/8/1/D_load openal32

mac 修改mysql端口_mac下的一些mysql操作-程序员宅基地

文章浏览阅读1.2k次。#一、从终端进入mysql不同于windows下的mysql。mac下的mysql安装路径不同,所以操作上会略有不同;以下操作以默认安装mysql为前提。##一(1):打开终端后,先设置路径,后面就不用每步操作都指定路径了(大小写区分):输入:PATH=“$PATH”:/usr/local/mysql/bin回车确认;再输入:mysql -uroot -p;(从此开始的操作都与windows版的一..._mac mysql5.5修改端口号

Java stream操作toMap总结_stream tomap-程序员宅基地

文章浏览阅读1.3w次,点赞10次,收藏23次。1、map 对象本身,重复的key,放入List。Map<String, List<Working>> map = workings.stream().collect(Collectors.toMap(Working::getInvoicePage, e -> { ArrayList<Working> list = new Arr_stream tomap

随便推点

maven 如何查看jar在哪个pom引入_maven查看jar包从哪个pom引入-程序员宅基地

文章浏览阅读4.8k次,点赞3次,收藏6次。窗口,然后选中项目(非项目不会出现该图标),再点击查看依赖关系图 Icon,如图所示。2、进入该页面进行 Ctrl + F 搜索需要的 Jar 名称。3、我这里以“hutool” jar为例。5、此时就会跳转到对应的 pom 坐标。4、找到并双击该高亮地方。_maven查看jar包从哪个pom引入

handsontable合并项mergeCells应用及扩展-程序员宅基地

文章浏览阅读782次。由于我这个项目主要是配置多表头信息,主要使用了handsontabel合并项功能。但是,在该功能使用过程中发现了一些问题和一些自己根据需要做的一些扩展 $("#topFieldDiv").handsontable({ data: data, colHeaders: colHeadArr,//设置列头 manualRowRe..._handsontable mergecells

Object.requireNonNull_objects.requirenonnull-程序员宅基地

文章浏览阅读4.3k次,点赞3次,收藏6次。Object.requireNonNullObject.requireNonNull介绍java8中的优化写法Object.requireNonNull源码Object.requireNonNull介绍Object.requireNonNull是用于参数有效性检查的API。使用Object.requireNonNull方法的好处在于可以显式的指定在哪里抛出异常。举个栗子public class Foo { private List<Bar> bars; public Foo(Lis_objects.requirenonnull

python提取pdf中图片和文本_python原生代码,提取pdf图片中的文字-程序员宅基地

文章浏览阅读734次。【代码】python提取pdf中图片和文本。_python原生代码,提取pdf图片中的文字

计算机二级office考试题库操作题,计算机二级考试MSOffice考试题库ppt操作题附答案...-程序员宅基地

文章浏览阅读2.1k次。请在【答题】菜单下选择【进入考生文件夹】命令,并按照题目要求完成下面的操作。 注意:以下的文件必须保存在考生文件夹下文慧是新东方学校的人力资源培训讲师,负责对新入职的教师进行入职培训,其PowerPoint演示文稿的制作水平广受好评。最近,她应北京节水展馆的邀请,为展馆制作一份宣传水知识及节水工作重要性的演示文稿。节水展馆提供的文字资料及素材参见\水资源利用与节水(素材).docx\,制作..._标题页包含演示主题,制作单位和日期

unity 启动相机_Unity3D研究院之打开照相机与本地相册进行裁剪显示(三十三)...-程序员宅基地

文章浏览阅读255次。最近做项目需要用到这个功能,就是在Unity中调用Android本地相册或直接打开摄像机拍照并且裁剪一部分用于用户头像,今天研究了一下,那么研究出成果了MOMO一定要分享给大家。Unity与Android的交互还有谁不会?? 如果有不会的朋友请看MOMO之前的文章喔,Unity3D研究院之打开Activity与调用JAVA代码传递参数(十八)这里有关交互的方式就不详细说明,主要将如何在Unity中..._unity打开照相机与本地相册进行裁剪

推荐文章

热门文章

相关标签