内存只增不减(非内存泄露)解决
在ADAS项目中,代码中加入了跟踪模块,使得程序的内存占用不断上升,但是却不是内存泄漏,断断续续经过近2周的排查,终于将问题解决,特此记录,希望对你有所帮助!
内存只增不减(非内存泄露)解决
微信公众号:幼儿园的学霸
个人的学习笔记,关于OpenCV,关于机器学习, …。问题或建议,请公众号留言;
在ADAS项目中,代码中加入了跟踪模块,使得程序的内存占用不断上升,但是却不是内存泄漏,断断续续经过近2周的排查,终于将问题解决,特此记录,希望对你有所帮助!
目录
缘起
在ADAS项目中,由于障碍物检测不是很稳定,某些时刻会出现“跳帧”现象,导致检测的目标框给人一种“一闪一闪”的感觉,因此考虑加入多目标跟踪,以弥补目标检测的不足。多目标跟踪代码是基于OpenCV的目标跟踪模块编写而成,加入之后发现程序的运行内存不断上升,大概4000帧视频,在我的电脑上内存可以从7.3%上升的23%左右,由于跟踪模块的实现均采用的智能指针,加上对代码的自信,因此我认为绝对不可能是内存泄露,但是内存上升的事实摆在这里,无法避免。没办法啦,采用valgrind
进行校验,未发现泄露。but,这样也不能解决内存上升的问题啊。so,开始了一遍一遍核对代码,甚至对跟踪代码进行了一遍又一遍的重写,但是问题依然无法解决,这玩意儿折磨了我快2周的时间,真是心累啊。
期间怀疑过是内存碎片的原因,但是当时对内存碎片没有了解,没有深入研究,所以放过了这个提前解决问题的机会(主要是当时不太认为内存碎片不会造成内存增长)。
解决
曙光
经过一遍一遍的折磨,准备放弃时,我感觉需要重新搜索一下内存碎片
,终于发现了下面这段话:
glibc的malloc分配的内存在free之后,并不一定会交还给操作系统,释放的内存会被glibc管理维护,方便下次malloc的时候继续使用。是有满足一定的条件的情况下,释放的内存才会交还给操作系统。在不断的malloc,free之后,某一进程会导致大量的内存碎片产生,这些内存碎片由于glibc的回收机制,很难被交还给操作系统。因而出现“内存泄漏”现象。来源:https://blog.csdn.net/Abrahampan/article/details/51601680
山重水复疑无路,柳暗花明又一村,非常感谢上面的作者,他的这句话给了我启发啊,解决了折磨我这么久的问题啊。
搞定
按照提示,安装tcmalloc
,过程小记:
1.安装libunwind
从http://download.savannah.gnu.org/releases/libunwind
下载libunwind-1.3.1.tar.gz
解压,
cd libunwind-1.3.1/
./configure #默认安装到/usr/local/lib
#or./configure --prefix=安装路径
make
sudo make install
2.安装gperftools
从https://github.com/gperftools/gperftools/releases/
下载gperftools-2.7.tar.gz
解压
cd gperftools-2.7/
./configure #默认安装到/usr/local/lib
#or./configure --prefix=安装路径,如/usr/local/lib/tcmaloc
make
sudo make install
3.配置以使生效
默认安装时,上述文件安装在/usr/local/lib
路径下,那么执行命令sudo /sbin/ldconfig
即可使库生效;
如果安装路径被人为指定,不在默认路径时,那么需要采用下面两行命令
echo "/usr/local/lib/tcmaloc(代表上面的安装路径)" > /etc/ld.so.conf.d/usr_local_lib.conf
sudo /sbin/ldconfig
4.使用:
1)将tcmalloc通过“-ltcmalloc”链接器标志接入你的应用;
2)通过使用LD_PRELOAD
在不是你自己编译的应用中使用tcmalloc,例如,对于我的ADAS程序,我可以按照如下命令执行:
export LD_PRELOAD=/usr/local/lib/libtcmalloc.so
./ADAS_usbCamera -ad ../configfile/usb_4mm_HD_CameraConfig.yaml
通过该方式执行下,程序内存占用如图:
使用前程序内存占用:
实验结果证明,使用tcmalloc后程序不再像以前那样内存只增不减
5.其他
通过参考链接中的资料可以发现,在代码的起始位置加入下面2行代码,也可以控制内存占用
mallopt(M_MMAP_MAX, 0); // 禁止malloc调用mmap分配内存
mallopt(M_TRIM_THRESHOLD, 0); // 禁止内存缩进,sbrk申请的内存释放后不会归还给操作系统
//头文件
//#include <malloc.h>
但是在我的实验中,发现内存任然上升,只是上升的速度降下来了,可能还需要其他方法配合吧(如malloc_trim(0)
,考虑在每一帧图像处理时,首先执行该函数一遍,实测该方法非常影响程序性能,建议慎用)。
总结
1.malloc()/free()作为C标准,ANSI C并没有指定它们具体应该如何实现。各个平台上(windows, mac, linux等等),调用这两个函数时,实现不一样;
2.不要盲目相信glibc, 它虽然是系统默认的,却不一定就好。glibc和stl搭档可能有问题
3.在linux下,malloc()/free()的实现是由glibc库负责的。STL的内存释放,有时候并没有直接返还给os,只是返还给了分配器;
4.针对大量数据,谨慎大量使用STL局部变量,虽然栈上分配的,但它维护的队列是分配在heap上的,它操作的内存不一定能够即使释放,可能产生碎片;
5.对于在堆上申请内存,是会产生一定代价的,特别是滥用,后果也是比较严重的。内存碎片是需要关注的问题。
代码都会写,如何写出高性能,高质量的代码,这玩意而真就是个技术活。
参考
- "內存碎片"疑似“内存泄漏”
- 几种malloc实现原理 ptmalloc(glibc) && tcmalloc(google) && jemalloc(facebook)
- Linux glibc 的 mallopt 海量小内存回收问题
- Linux Debugging (九) 一次生产环境下的“内存泄露”
- TCMalloc:线程缓冲的Malloc
- cmake:动态链接库(so)中静态链接tcmalloc(gperftools2.4)暨静态链接libstdc++
- Linux Allocator Does Not Release Small Chunks of Memory
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)