【问题标题】:pthread_create using 85MB VIRT instead of 8MB VIRTpthread_create 使用 85MB VIRT 而不是 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 位操作系统上,没有理由尝试将其最小化,因为它实际上是免费的。

标签: c memory-management pthreads heap-memory virtual


【解决方案1】:

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

【讨论】:

  • 我试过这个,出于某种原因,无论我将堆栈大小设置为多小或大,它对 htop 中报告的 VIRT 分配大小的影响为零。
  • @Grish 发布您的代码。
猜你喜欢
  • 2020-05-02
  • 1970-01-01
  • 2016-12-12
  • 1970-01-01
  • 2018-06-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-06-18
相关资源
最近更新 更多