c++ 多进程 内存泄漏问题求助

2022-09-11 05:08:33 +08:00
 ShinomiyaKaguya

我是 c++初学者,尝试使用多进程时遇到了诡异的内存泄漏的问题,这是全部代码。

在我本地的服务器用 valgrind 测试没有泄漏,但另一台服务器上就会出现泄漏问题,我百思不得其解,请大神给点思路

随附 cpp 源文件和 valgrind 的 log 的下载链接:

https://dropover.cloud/9552c4

#include <string.h>
#include <regex>
#include <sys/wait.h>
#include <unistd.h>

int test(std::string input, std::string output){ int status = 0;

pid_t pid;
for (int i = 0; i &lt; 10; i++) {
    pid = fork();
    
    if (pid == 0) {
        exit(0);

    }
    else if (pid &lt; 0) {
        perror("fork");
        exit(1);
    }
    else {
        waitpid(pid, &amp;status, 0);
    }
    
}
// memery leak

return 0;

}

int main(int argc, char *argv[]) { std::string input = "1"; std::string output = "2";

test(input, output);  

return 0;

}

1796 次点击
所在节点    问与答
17 条回复
vsyf
2022-09-11 10:32:07 +08:00
可以看到没有泄露
ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

still reachable 的应该是 2 个 string ,和标准库的实现有关吧。
https://valgrind.org/docs/manual/faq.html#faq.reports
codyfeng
2022-09-11 11:28:44 +08:00
一个可能性:旧版 gcc 的 std::string 用的 copy-on-write ,多个 copy 用的是同一个 buffer ,不是线程安全的。可以将尝试`test(input, output);`改为`test(input.c_str(), output.c_str());`看看是否能解决
majula
2022-09-11 12:06:44 +08:00
我在自己开发机上面测试没有复现

楼主还是发下出问题的 gcc 和 libstdc++ 版本吧
ShinomiyaKaguya
2022-09-11 12:41:25 +08:00
@vsyf
@codyfeng
确实是 string 的问题,换成 c 语言的 char[] 就不泄漏了

@majula
出问题的机器是
gcc (GCC) 9.3.1 20200408 (Red Hat 9.3.1-2)

libstdc++.so.6 (libc6,x86-64) => /lib64/libstdc++.so.6
libstdc++.so.6 (libc6) => /lib/libstdc++.so.6
的确是旧版本的 gcc ,但我用的是 g++来编译的,这之间有什么影响吗
BrettD
2022-09-11 12:51:44 +08:00
在出问题的环境里, _GLIBCXX_USE_CXX11_ABI 宏的默认值是多少?
ShinomiyaKaguya
2022-09-11 13:05:56 +08:00
@BrettD
有没有什么命令来查看默认值,我没查到怎么看
BrettD
2022-09-11 13:10:08 +08:00
最简单方法就直接写一段 C++代码,用#ifdef 检查有没有定义这个宏,如果有的话用 cout 输出这个宏
ShinomiyaKaguya
2022-09-11 13:28:27 +08:00
BrettD
2022-09-11 13:38:22 +08:00
那有可能是 2 楼说的 CoW String 原因,试一下编译参数-D_GLIBCXX_USE_CXX11_ABI=1 再试
ShinomiyaKaguya
2022-09-11 14:21:29 +08:00
@BrettD 我用这条命令编译,还是内存泄漏,但现在改用 char[]就没问题了
g++ -Wall -Werror -std=c++14 -D_GLIBCXX_USE_CXX11_ABI=1 -O -o task2 task2.cpp
BrettD
2022-09-11 16:19:31 +08:00
你的系统是 RHEL 6 或者 7 吗?在 RHEL 6 和 7 上,_GLIBCXX_USE_CXX11_ABI 是被强制禁用的,即使手动设定了这个宏,编译出来的程序还是使用的旧 ABI 下的 COW 的 std::string ,可能导致了 Valgrind 报告 still reachable 。如果在 RHEL 8 或者更新的系统上面启用_GLIBCXX_USE_CXX11_ABI ,就没有这个报告了。
BrettD
2022-09-11 16:20:22 +08:00
我在 Rocky Linux 9 上面手动制定-D_GLIBCXX_USE_CXX11_ABI=0 成功复现了这个问题,默认情况下_GLIBCXX_USE_CXX11_ABI=1 就没有这个问题。
BrettD
2022-09-11 16:28:40 +08:00
如果在你的 test 函数中把
if (pid == 0) {
exit(0);
}
改成
if (pid == 0) {
return 0;
}
Valgrind 就不再报告 still reachable 了。
BrettD
2022-09-11 16:30:58 +08:00
如果你使用 exit(0)退出进程,main 函数中的 string 对象的析构函数就不会被调用,所以可能导致了“内存泄漏”。如果改成 return 0 ,控制流会回到 main 函数,然后在 main 函数 return 0 之后,main 函数中的 string 对象的析构函数被调用。
ShinomiyaKaguya
2022-09-11 16:58:42 +08:00
@BrettD
厉害,改成 return 0 就不泄漏了
我的系统是 red hat 7.9 ,可能和 rocky 一样禁用了这个参数
BrettD
2022-09-11 17:04:13 +08:00
你再仔细看一遍,我说的是 RHEL 6/7 是禁用 CXX11ABI ,我是 Rocky 9 ,和 RHEL 9 等效,RHEL 8/9 是可以使用 CXX11ABI 的
ShinomiyaKaguya
2022-09-11 20:31:10 +08:00
@BrettD 抱歉,是 RHEL6/7 禁用,可能我的系统和 RHEL 一样禁止修改了这个参数

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/879220

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX