pthread_create 使用 85MB VIRT 而不是 8MB VIRT

Posted

技术标签:

【中文标题】pthread_create 使用 85MB VIRT 而不是 8MB VIRT【英文标题】:pthread_create using 85MB VIRT instead of 8MB VIRT 【发布时间】:2021-11-13 10:51:29 【问题描述】:

好的,我理解 VIRT != 物理 RAM,通常建议不要担心它等。

但我很困惑为什么我的每个 pthread_create 都会导致 VIRT 增加 85MB,而不是根据我的 ulimit 堆栈设置 8192 kbytes 通常增加 8MB。

我怀疑它与堆有关,但我是 C 新手,不确定这方面。

我的代码片段是:

if (tcount == gset_vars->global_threads_max)

    for (j = 0; j< tcount; j++)
    
        pthread_join(tid[j], NULL); // close threads
    
    tcount=0;

pthread_create(&tid[tcount],NULL,HTTP_Multi_Thread,(void *)&args[i]);
tcount++;

代码注释:

它在一个for循环中,有15次迭代,得到的VIRT是1275MB(即15*85)

内部 for 循环仅在 gset_vars->global_threads_max 变量设置为小于 15 时运行(这不会影响生成的 VIRT 大小)。

函数调用 (HTTP_Multi_Thread) 只是运行一些基本的 libcurl 来下载单个文件并将其写入磁盘。 args 只是 url 和本地文件名。

注意:为了保持代码 sn-p 简短,它没有显示在主循环之后我确实在所有线程上运行 pthread_join (tcount)。

编辑:正如@johnbollinger 所建议的,这里是一个基本的、可重现的示例:

#include <stdio.h>
#include <pthread.h>
#include <curl/curl.h>
#include <string.h>
#include <unistd.h>

#define NUMT 8

char *urls[NUMT] = 
    "http://example.com",
    "http://example.com",
    "http://example.com",
    "http://example.com",
    "http://example.com",
    "http://example.com",
    "http://example.com",
    "http://example.com";

char *filenames[NUMT] = 
    "ex1.txt",
    "ex2.txt",
    "ex3.txt",
    "ex4.txt",
    "ex5.txt",
    "ex6.txt",
    "ex7.txt",
    "ex8.txt";

struct arg_struct

    char url[128];
    char filename[128];
;

size_t write_data(void *ptr, size_t size, size_t nmemb, FILE *stream)

    size_t written = fwrite(ptr, size, nmemb, stream);
    return written;


static void *pull_one_url(void *arguments)

    struct arg_struct *myargs = arguments;
    char url[128];
    char filename[128];
    strcpy(url, myargs->url);
    strcpy(filename, myargs->filename);
    FILE *fp;
    fp = fopen(filename, "wb");
    CURL *curl;
    curl = curl_easy_init();
    curl_easy_setopt(curl, CURLOPT_URL, url);
    //curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data);
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
    curl_easy_perform(curl);
    curl_easy_cleanup(curl);
    fclose(fp);
    return NULL;


int main(int argc, char **argv)

    pthread_t tid[NUMT];
    int i;
    struct arg_struct args[NUMT];

    curl_global_init(CURL_GLOBAL_ALL);
    for (i = 0; i < NUMT; i++)
    
        strcpy(args[i].filename, filenames[i]);
        strcpy(args[i].url, urls[i]);
        pthread_create(&tid[i],
                       NULL,
                       pull_one_url,
                       (void *)&args[i]);
    

    for (i = 0; i < NUMT; i++)
    
        pthread_join(tid[i], NULL);
        fprintf(stderr, "Thread %d terminated\n", i);
    
    curl_global_cleanup();
    sleep(60);

sleep(60) 的唯一目的是在运行时允许一些分析时间。可能需要为 Windows 用户启用 WRITEFUNCTION 选项。

【问题讨论】:

如果您希望我们考虑您的代码细节与问题相关的可能性,那么我们肯定需要一个 minimal reproducible example 来重现行为。 感谢@JohnBollinger 我在我的主帖中添加了一个基本示例。有趣的是,这个例子为每个线程分配了大约 135MB 的 VIRT,至少根据我的 64 位 raspbian 操作系统上的 htop。 我没有要求一个基本的例子,我要求的是一个最小的。那是你提供的吗?例如,您能否在不消除大量虚拟内存占用的情况下删除对 libcurl 函数的任何调用?如果有的话,哪些对于观察您所询问的行为至关重要? 如果将curl_easy_init()curl_easy_cleanup() 调用移至主线程,并在其间向每个线程传递一个(不同的)句柄会怎样? @Grish 由于虚拟内存不是稀缺资源,因此分配大量虚拟内存绝对没有什么可笑的。有些应用程序分配 2GB 或更多的虚拟内存只是为了使文件访问更简单一些。在 64 位操作系统上,没有理由尝试将其最小化,因为它实际上是免费的。 【参考方案1】:

您的ulimit 堆栈设置仅影响进程的起始堆栈。它对新创建线程的堆栈大小没有任何影响。为此,您需要使用pthread_attr_setstacksize

【讨论】:

我试过这个,出于某种原因,无论我将堆栈大小设置为多小或大,它对 htop 中报告的 VIRT 分配大小的影响为零。 @Grish 发布您的代码。

以上是关于pthread_create 使用 85MB VIRT 而不是 8MB VIRT的主要内容,如果未能解决你的问题,请参考以下文章

富士通代理I2C接口FRAM芯片MB85RC16V

正确使用pthread_create,防止内存泄漏

使用 pthread_create 时出现 valgrind 内存泄漏错误

C++:使用 pthread_create 创建新线程,以运行类成员函数

如何在 pthread_create() 函数中将矩阵作为参数传递?

在 TCP 服务器中使用 pthread_create 时出现错误 11