процесс и потоки потребляют много памяти после выполнения задания

#c #linux #multithreading #memory

#c #linux #многопоточность #память

Вопрос:

недавно я столкнулся с некоторой проблемой, связанной с потоком памяти. Приведенный ниже код создает 5 потоков, и каждый поток возвращает вектор 500’000’000 значений int. После завершения цикла с push_back программа по-прежнему использует ~ 375 Мб виртуальной памяти, и вот мой вопрос, почему процесс по-прежнему использует так много памяти?

Я использую g (Ubuntu 8.4.0-1ubuntu1 ~ 18.04) 8.4.0

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

using namespace std;
  

void joinAll(vector<thread>amp; arg)
{
    for(autoamp; item : arg) item.join();
}

int main()
{

    vector<thread> threads;
    
    for(int i=0; i<5;   i)
    {
        threads.emplace_back([](){
            
            {   // block
                vector<int> data;
                
                for(int idx=0; idx<500'000'000;   idx)
                {
                        data.push_back(idx);    
                }
            }   // end of block
            
            cout<<"loop is overn";
            
            std::this_thread::sleep_for(chrono::seconds(5));
            
            });
    }    
    
    cout<<"wait in mainn";  
    
    std::this_thread::sleep_for(std::chrono::seconds(5));
    
    joinAll(threads);
        
}
 

Изображение представляет htop вывод

введите описание изображения здесь

Комментарии:

1. Вы никогда не проверяете наличие каких-либо исключений из дескриптора памяти / ресурсов. Неперехваченные исключения в потоках и продолжающееся выполнение могут привести к общему неопределенному поведению . Множество возможностей позволить вашей ОС зависнуть.

2. Для записи в этом примере создаются векторы с элементами 1B, а не 500M. Сначала он определяет вектор с 500 миллионами элементов, а затем добавляет еще 500 миллионов.

3. Виртуальная память обычно не возвращается в ОС в тот момент, когда она больше не используется. Насколько известно операционной системе, процесс собирается создать еще один огромный вектор — нет смысла переносить память туда и обратно. ОС восстановит эту память, когда процесс завершится или когда другой процесс запросит виртуальную память, а в ОС ее нет. Более эффективно освобождать неиспользуемую память только при нехватке памяти — в большинстве случаев ее достаточно.

4. Скомпилируйте свой код C с помощью вызываемого GCC , а g -Wall -Wextra -O2 -g затем используйте strace(1) и gdb (1) , чтобы понять поведение и системные вызовы (2) , выполняемые вашим исполняемым файлом

Ответ №1:

Для процесса не требуется возвращать свою память обратно в ОС в тот момент, когда она больше не используется. Также было бы очень неэффективно, если бы было такое требование.

Кроме того, давайте проведем быстрый анализ требований к памяти вашей программы. Предполагая, что типичный случай int равен 4 байтам, и предполагая, что ваши потоки выполняются параллельно и заканчиваются в одно и то же время, тогда вашей программе требуется около 2,5 ГБ только для ваших vector s, не говоря уже о требованиях к памяти для самих потоков и любой другой памяти процесса. Тот факт, что вы видите только использование ~ 375 МБ, указывает на то, что память процесса в значительной степени возвращается в ОС.