虚拟内存大小随着线程数量的增加而显着增加

问题描述 投票:0回答:1

在下面的 C++ 代码示例中,每次用户按“Enter”键时,都会创建一个新线程。该线程等待 10 分钟并退出。该线程有一个带有一些字符串的“std::string”对象。

#include <iostream>
#include <thread>
#include <chrono>
#include <string>
#include <vector>

using namespace std;

// Function that each thread will execute
void threadFunction()
{
    std::string str;
    str = "abcdefghijklmnopqrstuvwxyz";

    std::cout << "--------------> Thread created" << std::endl;
    // Sleep for 10 minutes'
    this_thread::sleep_for(chrono::minutes(10));
    cout << "Thread finished sleeping for 10 minute!" << endl;
}

int main()
{
    char input;
    while (true)
    {
        cout << "Press Enter to create a new thread, or 'q' to quit: ";
        input = getchar(); // Wait for user input

        if (input == '\n')
        {                                     // If Enter key is pressed
            thread newThread(threadFunction); // Create a new thread
            newThread.detach();               // Detach the thread to let it run independently
        }
        else if (input == 'q')
        { // If 'q' is pressed, quit the program
            break;
        }
        // Ignore any other input
        cin.ignore(numeric_limits<streamsize>::max(), '\n');
    }

    return 0;
}

对于每个线程(按下输入键),可以观察到虚拟内存显着增加。 enter image description here 使用命令“htop”检查

OS : Ububtu 20.04.6 LTS (Focal Fossa)
gcc: gcc (Ubuntu 9.4.0-1ubuntu1~20.04.2) 9.4.0

注意:在 Windows(mscv) 中未观察到此问题。

任何人都可以帮助解释为什么会发生这种情况以及如何解决它吗?根本原因是什么?我们该如何解决?

c++ linux gcc virtual-memory stdthread
1个回答
0
投票

您可以查看调试器中的情况:

#0  __GI___mmap64 (addr=addr@entry=0x0, len=len@entry=134217728, prot=prot@entry=0, flags=flags@entry=34, fd=fd@entry=-1, 
    offset=offset@entry=0) at ../sysdeps/unix/sysv/linux/mmap64.c:50
#1  0x00007ffff7ab2895 in alloc_new_heap (size=135168, top_pad=<optimized out>, pagesize=4096, mmap_flags=mmap_flags@entry=0)
    at ./malloc/arena.c:518
#2  0x00007ffff7ab29e6 in new_heap (size=size@entry=2904, top_pad=<optimized out>) at ./malloc/arena.c:573
#3  0x00007ffff7ab2db2 in _int_new_arena (size=640) at ./malloc/arena.c:741
#4  arena_get2 (avoid_arena=<optimized out>, size=640) at ./malloc/arena.c:960
#5  arena_get2 (size=640, avoid_arena=<optimized out>) at ./malloc/arena.c:921
#6  0x00007ffff7ab5554 in tcache_init () at ./malloc/malloc.c:3220
#7  0x00007ffff7ab5cfe in tcache_init () at ./malloc/malloc.c:3217
#8  __GI___libc_malloc (bytes=31) at ./malloc/malloc.c:3282
#9  0x00007ffff7cb268c in operator new(unsigned long) () from /lib/x86_64-linux-gnu/libstdc++.so.6
#10 0x00007ffff7d4fe1e in std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_mutate(unsigned long, unsigned long, char const*, unsigned long) () from /lib/x86_64-linux-gnu/libstdc++.so.6
#11 0x00007ffff7d50f0b in std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_replace(unsigned long, unsigned long, char const*, unsigned long) () from /lib/x86_64-linux-gnu/libstdc++.so.6
#12 0x0000555555555254 in threadFunction() ()

glibc 在第一次分配时为每个线程分配一个新的线程局部区域。如果删除

std::string
,则不会发生分配,因此不会创建 arena,vspace 使用量只会根据堆栈的大小而增长。

arena 本身相对较小,但由于 对齐原因,glibc 分配了比所需更大的大小:

  /* A memory region aligned to a multiple of max_size is needed.
     No swap space needs to be reserved for the following large
     mapping (on Linux, this is the case for all non-writable mappings
     anyway). */
© www.soinside.com 2019 - 2024. All rights reserved.