Linux进程优化:内存泄漏怎么办

嘿,内存泄漏在 Linux 系统中是相当烦人的……在 2 02 2 年,我经历过好几次。
CPU和内存不断增加,最终系统死机。
直到那时我才意识到我需要系统地去做。

先说说立场吧。
当时我先用top查看,查看RES和%MEM,发现有一个进程内存不断增加。
然后,我换成htop,按内存排序,运行一下,发现是临时文件,生成的东西太多了。
如果仍然不起作用,请使用 Valgrind。
例如,对于程序 ./my_program,运行: valgrind --leak-check=full --show-leak-kinds=all ./my_program。
它输出诸如“明确丢失:1 个块中的 1 02 4 个字节”、“隐式丢失:2 个块中的 2 04 8 个字节”之类的内容,并且您必须查看堆栈跟踪以找出代码的哪一部分存在问题。
如果与内核相关,请使用 kmemleak。
必须先打开 echo 1 > /sys/kernel/debug/kmemleak,cat /sys/kernel/debug/kmemleak 看是否有泄漏,使用后关闭 echo 0 > /sys/kernel/debug/kmemleak。
然而,这需要内核支持CONFIG_DEBUG_KMEMLEAK,这有时会影响性能。

发现问题并解决它们。
最基本的就是尽快释放内存。
不要这样做: int arr = malloc(1 0 sizeof(int)); if (arr != NULL) { // 使用 arr... free(arr); // 这一步必须做 arr = NULL; // 避免野指针 }.注意C++中的循环引用,并使用std::weak_ptr来打破它们。
例如,std::shared_ptr a = std::make_shared(); std::weak_ptr b = a;那么b就是弱引用,不会造成死锁。
如果这不起作用,只需查看 Valgrind 报告的堆,或者查看 kmemleak 日志以查找未发布的内核代码中的分配块。

修复还不够,还需要预防。
一种方法是创建内存池,比如用C写mempool_alloc和mempool_free,或者用C++写boost::pool。
原则是先获取大块内存,需要小块内存时再从中划分,以减少频繁和空闲的malloc。
编码也必须标准化。
在 C++ 中使用智能指针。
不要混合使用 malloc 和 new,因为这很容易导致问题。
在编写单元测试时,需要模拟异常情况,例如函数抛出异常时是否会释放内存。
压力测试也很重要。
让程序运行几天,看看内存是否继续增长。
还有 cppcheck 和 clang-tidy 等工具可以帮助您及早发现问题。
关于内核,可以打开CONFIG_DEBUG_VM和CONFIG_SLUB_DEBUG等调试选项,并在主要位置添加打印输出或其他内容以方便查看。

简而言之,需要使用topaudit、Valgrind、kmemleak和code进行排名。
维修应及时免费,使用智能指示器并听取工具报告。
为了避免这种情况,你需要构建一个内存池,编写好的代码,进行更多的测试,使用静态分析工具,并在内核中打开一些调试项。
这样做可以减少内存泄漏问题,使系统更加稳定。

【test】kunit/ktest/CuTest机制介绍

记得有一次,我在一个开源项目中负责核心模块的开发。
该模块的功能比较复杂,涉及多个子模块和外部接口。
当时我们团队在测试阶段遇到了一些困难。
测试用例繁琐,每次测试都需要重启系统,这无疑拖慢了开发进度。

后来我们尝试引入KUnit进行单元测试。
我花了两天时间熟悉了KUnit的API,然后开始编写测试用例。
KUnit 的轻量级设计给我留下了深刻的印象。
它几乎不需要修改核心代码,可以快速集成到我们的开发流程中。
我记得有一次我在使用KUnit的assert函数测试一个内存分配子模块时,发现了一个内存泄漏的问题。
那天晚上我加班修复了这个bug。
第二天一早,我就收到了测试团队的反馈,测试已经通过,模块运行稳定。

但我也注意到KUnit更适合测试核心模块。
对于一些复杂的系统级测试,我们还需要像KTest这样的自动化测试框架。
KTest 自动化回归测试和性能测试的能力在我们的项目中也发挥着重要作用。

然后我还发现了一个有趣的事情。
我们项目的某些部分是用C语言编写的,CuTest用于测试这些部分。
CuTest的简单性和独立性给我留下了深刻的印象,我什至能够在一个周末完成一个复杂模块的测试。

等等,还有一件事,我突然想到,如果我们在测试阶段能够发现更多的bug,是不是能够进一步提高代码质量呢?不过,这需要我们不断优化测试流程,引入更多的测试工具。
看来测试工作永远不会结束。