#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 МБ, указывает на то, что память процесса в значительной степени возвращается в ОС.