【问题标题】:C program causes memory leak?C程序导致内存泄漏?
【发布时间】:2019-10-21 10:01:45
【问题描述】:

我使用那个非常简单的 C 程序每秒执行一个对 php 的系统调用,以便运行一个 php 脚本,将我数据库中的待处理推送通知发送到 APNS(Apple 通知服务)。

无论如何,这个程序会在大约 10 小时后导致内存溢出,因此我将线程创建之间的睡眠时间从 1 秒减少到 10000 微秒,并且我可以通过htop 实时看到内存在不断增加,而且从未降低。这是程序:

#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>

typedef struct {
    char* script_path ;
} arg_for_script ;

static void *start_instance(void *_args)
{
    int id = abs(pthread_self());
    arg_for_script* args = _args ;

    printf("[SERVICE] start php script on thread %d\n",id);
    fflush(stdout);
    char cmd[200] ;

    sprintf(cmd, "php -f %s %d", args->script_path, id );

    system(cmd);

    printf("[SERVICE] end of script on thread %d\n", id);
    fflush(stdout);



    pthread_exit(NULL);
}

int main(int argc, char* argv[])
{


    if(argc < 2)
    {
        fprintf(stderr, "[SERVICE] Path of php notification script must be filled\n");
        fflush(stderr);
        return EXIT_FAILURE;
    }

    arg_for_script args ;

    args.script_path = argv[1];

    pthread_attr_t tattr ;
    struct sched_param param;
    param.sched_priority = 1 ;

    pthread_attr_init(&tattr);

    pthread_attr_setinheritsched(&tattr, PTHREAD_EXPLICIT_SCHED);
    pthread_attr_setschedpolicy(&tattr, SCHED_FIFO);
    pthread_attr_setschedparam(&tattr, &param);



    while(1) {
        pthread_t thrd;

      //  if(pthread_create(&thrd, &tattr, start_instance, (void *)&args) == -1) {
        if(pthread_create(&thrd, NULL, start_instance, (void *)&args) == -1)
        {
            fprintf(stderr, "[SERVICE] Unable to create thread\n");
            fflush(stderr);
            return EXIT_FAILURE;
        }

        usleep( 10000);
    }

  //  pthread_attr_destroy(&tattr);
    return EXIT_SUCCESS ;

}

在这里,我不会使用malloc 动态分配任何 RAM。为什么这个程序会增加内存使用量?我应该在这里free 什么指针?

【问题讨论】:

    标签: c memory-leaks pthreads


    【解决方案1】:

    您没有调用pthread_join(),也没有使用pthread_detach(),因此分配给线程的资源不会被释放。即每个线程都有自己的堆栈,这可能是导致内存消耗上升的原因。

    关于您的实现的一些评论:由于您计划使用 system() 执行 PHP 脚本并且实际上不需要处理共享变量或文件描述符,因此最好使用 fork() 和 @ 的变体之一987654327@。这将产生一个新进程,而无需创建线程的中间步骤。也不建议使用system(),因为它通常允许在输入未正确清理时利用程序。在这种情况下,如果您只手动调用它可能会很好。

    【讨论】:

    • 感谢 pthread_detach() :) 实际上我的 php 脚本包含:(1)从 db 检索所有待处理标记的通知并将它们标记为在 db 中发送(2)通过 TCP 将它们发送到 Apple。我希望如果任何 php 脚本正在执行 (1),我的 c 程序中的互斥锁会阻止任何新线程的创建(如果有 100K 待处理的通知一次发送,则数据库中的读/写操作最多可能需要 5 分钟..,如果在这种情况下从 C 调用新脚本,则 2 个脚本可以检索相同的通知并将其发送两次给 Apple)。对于第(2)部分,可以让新线程创建。这种行为可以在没有线程的情况下完成?
    • 这取决于您打算如何检查情况 (1) 是否正在发生。使用线程时如何检查该条件,php 脚本是否将某些内容打印到标准输出?如果是这种情况,您可以使用 exec 并使用管道将输出重定向到您的 c 程序(看看如何使用dup2)。不过我想知道,为什么不扩展 php 脚本以定期检查条件 (1) 并轮询是否有新通知待处理,这可能是最直接的解决方案。
    • 我只想使用 cron 执行的 php 脚本,但 cron 无法启动第二周期任务(分钟是 cron 的最短单位)。 PHP 脚本产生输出,但这是英语更适用于想要查看 journalctl 发生了什么的开发人员。我还可以生成一个包含一位 (1/0) 的额外文件,但这不是一个非常方便的解决方案。我想过信号,它们是为此而设计的吗?我可以从 php 向 C 父进程发出一个信号,该信号不断分叉以防止它创建任何新的分叉,直到它收到一个“继续”信号?
    • 我觉得你正试图以一种非常复杂的方式解决这个问题。您为什么不扩展 php 脚本以无限期运行,并偶尔检查一下 php 脚本是否必须处理新数据。然后你只需要启动一次脚本就可以在后台运行nohup php script.php &amp;
    • 我想让我的推送通知有时能够一次发送大量通知。通过 TCP 向 Apple 发送 10 万条通知可能需要大约 15 分钟。同时,可能会出现新的待处理通知,我需要立即发送它们,因此即使有另一个进程当前正在发送大量其他通知,我也需要每秒轮询 db 并创建新的 TCP con。这就是为什么我创建了这个复杂的解决方案,但我不太习惯这一切(系统编程),所以如果你有更好的解决方案来实现这个灵活的目的,我真的很感激
    猜你喜欢
    • 2017-02-20
    • 2016-03-14
    • 1970-01-01
    • 2011-06-25
    • 2011-07-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多