V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
ShinomiyaKaguya
V2EX  ›  问与答

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

  •  
  •   ShinomiyaKaguya · 2022-09-11 05:08:33 +08:00 · 1768 次点击
    这是一个创建于 806 天前的主题,其中的信息可能已经有所发展或是发生改变。

    我是 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;
    

    }

    17 条回复    2022-09-11 20:31:10 +08:00
    vsyf
        1
    vsyf  
       2022-09-11 10:32:07 +08:00   ❤️ 1
    可以看到没有泄露
    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
        2
    codyfeng  
       2022-09-11 11:28:44 +08:00   ❤️ 1
    一个可能性:旧版 gcc 的 std::string 用的 copy-on-write ,多个 copy 用的是同一个 buffer ,不是线程安全的。可以将尝试`test(input, output);`改为`test(input.c_str(), output.c_str());`看看是否能解决
    majula
        3
    majula  
       2022-09-11 12:06:44 +08:00   ❤️ 1
    我在自己开发机上面测试没有复现

    楼主还是发下出问题的 gcc 和 libstdc++ 版本吧
    ShinomiyaKaguya
        4
    ShinomiyaKaguya  
    OP
       2022-09-11 12:41:25 +08:00 via iPhone
    @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
        5
    BrettD  
       2022-09-11 12:51:44 +08:00 via iPhone
    在出问题的环境里, _GLIBCXX_USE_CXX11_ABI 宏的默认值是多少?
    ShinomiyaKaguya
        6
    ShinomiyaKaguya  
    OP
       2022-09-11 13:05:56 +08:00
    @BrettD
    有没有什么命令来查看默认值,我没查到怎么看
    BrettD
        7
    BrettD  
       2022-09-11 13:10:08 +08:00 via iPhone
    最简单方法就直接写一段 C++代码,用#ifdef 检查有没有定义这个宏,如果有的话用 cout 输出这个宏
    ShinomiyaKaguya
        8
    ShinomiyaKaguya  
    OP
       2022-09-11 13:28:27 +08:00 via iPhone
    BrettD
        9
    BrettD  
       2022-09-11 13:38:22 +08:00 via iPhone
    那有可能是 2 楼说的 CoW String 原因,试一下编译参数-D_GLIBCXX_USE_CXX11_ABI=1 再试
    ShinomiyaKaguya
        10
    ShinomiyaKaguya  
    OP
       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
        11
    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
        12
    BrettD  
       2022-09-11 16:20:22 +08:00
    我在 Rocky Linux 9 上面手动制定-D_GLIBCXX_USE_CXX11_ABI=0 成功复现了这个问题,默认情况下_GLIBCXX_USE_CXX11_ABI=1 就没有这个问题。
    BrettD
        13
    BrettD  
       2022-09-11 16:28:40 +08:00   ❤️ 1
    如果在你的 test 函数中把
    if (pid == 0) {
    exit(0);
    }
    改成
    if (pid == 0) {
    return 0;
    }
    Valgrind 就不再报告 still reachable 了。
    BrettD
        14
    BrettD  
       2022-09-11 16:30:58 +08:00
    如果你使用 exit(0)退出进程,main 函数中的 string 对象的析构函数就不会被调用,所以可能导致了“内存泄漏”。如果改成 return 0 ,控制流会回到 main 函数,然后在 main 函数 return 0 之后,main 函数中的 string 对象的析构函数被调用。
    ShinomiyaKaguya
        15
    ShinomiyaKaguya  
    OP
       2022-09-11 16:58:42 +08:00 via iPhone   ❤️ 1
    @BrettD
    厉害,改成 return 0 就不泄漏了
    我的系统是 red hat 7.9 ,可能和 rocky 一样禁用了这个参数
    BrettD
        16
    BrettD  
       2022-09-11 17:04:13 +08:00 via iPhone
    你再仔细看一遍,我说的是 RHEL 6/7 是禁用 CXX11ABI ,我是 Rocky 9 ,和 RHEL 9 等效,RHEL 8/9 是可以使用 CXX11ABI 的
    ShinomiyaKaguya
        17
    ShinomiyaKaguya  
    OP
       2022-09-11 20:31:10 +08:00 via iPhone
    @BrettD 抱歉,是 RHEL6/7 禁用,可能我的系统和 RHEL 一样禁止修改了这个参数
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5154 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 28ms · UTC 01:22 · PVG 09:22 · LAX 17:22 · JFK 20:22
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.