Возврат динамически распределенной памяти обратно в ОС без завершения программы

Я работаю над программой, в которой я использую большой, но ограниченный объем памяти. Память выделяется и освобождается во время выполнения в разных потоках. Однако я заметил, что использование памяти программой не останется в указанных пределах. Со временем оно увеличится. Я написал следующий пример программы, чтобы проверить, освобождается ли память обратно в ОС. Половина выделенной памяти была освобождена, чтобы проверить, сократилось ли использование памяти.

int main()
{
    char *p[COUNT];

    for(int i = 0; i < COUNT; i++)
    {
        p[i] = new char[1048576];
        memset (p[i], 0, 1048576);
        printf("%p\n", p[i]);
    }

    printf("done allocating ... \n");

    sleep(10);

    printf("Freeing\n");
    for(int i; i < COUNT; i++)
    {
        delete[] p[i];
    }

    while(1)
        sleep(1);
}

После запуска программы казалось, что ОС не вернет освобожденные страницы. Использование памяти остается таким же, как видно из команды "top" в linux, после выделения и после освобождения. Он просто помечает страницы как свободные для повторного использования той же программой. В моей программе malloc и free работают в разных потоках. Это создает проблему управления памятью, когда malloc вызывается намного чаще, чем бесплатно, а сегмент данных процесса становится очень большим, что приводит к тому, что ОС переставляет страницы на диск. Это делает программу и ОС медленными и не отвечает. Есть ли способ для ОС вернуть освобожденную память?

 user329624711 мар. 2014 г., 11:39
@Dieter Lucking, просто высвободив половину выделенной памяти, чтобы увидеть, уменьшается ли использование памяти
 user329624711 мар. 2014 г., 12:10
Я прошу прощения за старую версию программы. Позвольте мне добавить обновленную версию.
 molbdnilo11 мар. 2014 г., 12:07
У вас определенно есть проблема с управлением памятью - эта программа никогда не освобождает память вообще.
 Dieter Lücking11 мар. 2014 г., 11:35
выделить 2000 против освобождения 1000 ???
 user329624711 мар. 2014 г., 12:23
@DavidSchwartz Спасибо, что нашли небольшую, но значительную ошибку. Я тестировал эту программу с помощью malloc_trim (0) и задавался вопросом, почему она все еще не освобождает память. После исправления проблемы с циклом я смог вернуть память обратно в ОС. :)
 David Schwartz11 мар. 2014 г., 12:18
@ user3296247 Ну, у тебя было много ошибок, у тебя все еще может быть больше. Не правильно зацикливание было ошибкой. Не спящий и, следовательно, потребляющий процессор был ошибкой. Продолжайте устранять неполадки, и, возможно, вы найдете больше проблем.
 David Schwartz11 мар. 2014 г., 12:01
Что вы подразумеваете под «но на этот раз освобождая всю память»? Не совсем понятно, что вы делаете. (Кроме того, ваш код никогда не устанавливаетсяi вернуться к 0 до второгоfor цикл.)
 Graham Griffiths11 мар. 2014 г., 12:15
Дэвид Шварц прав, ваш второй цикл никогда не будет выполнен, потому что вы не устанавливаете i в ноль для начала. Лучше запишите свои циклы for как: for (int i = 0; i <2000; i ++) (желательно сохранить переменную цикла локализованной, если это возможно). Если вы настаиваете на объявлении вне цикла, тогда оно должно быть: int i; для (i = 0; i <2000; i ++)
 user329624711 мар. 2014 г., 12:09
@DavidSchwartz, в вышеприведенной программе malloc повторяется до 2000 и freee () до 1000. На этот раз оба цикла до 2000 итераций, следовательно, освобождают столько, сколько выделено. Тем не менее, эта программа не прекращается после выделения и освобождения. Его просто позволяют жить в памяти, и запускается другой экземпляр той же программы. Кроме того, sleep (1) был добавлен в тело последнего цикла while, чтобы этот бесконечный цикл не сбрасывал процессор. Новый экземпляр той же программы работает медленно
 David Schwartz11 мар. 2014 г., 11:38
Вы не правы. Сохранение виртуальной памяти не делает ни программу, ни ОС медленной и не отвечает. ОС действительно освобождает физическую память. Восстановление виртуальной памяти не имеет смысла, потому что это не дефицитный ресурс.
 user329624711 мар. 2014 г., 11:58
@DavidSchwartz система действительно становится медленной. Я запустил ту же программу, как показано выше, но на этот раз освободил всю память. Программа работает быстро и способна выделить и освободить всю память за 2-3 секунды. Однако, когда я снова запускаю ту же программу, не завершая предыдущий процесс, новому процессу очень медленно выделяется память. kswap (процесс подкачки ядра) становится активным при высокой загрузке ЦП. Хотя ОС освобождает освобожденную память, она восстанавливает только тогда, когда в этом есть необходимость, а процесс восстановления замедляет работу системы. Может ли ОС мгновенно восстанавливать, когда вызывается free?

Ответы на вопрос(2)

используемая процессом, будет возвращена. Операционная система может сохранять данные спекулятивно кэшированными на всякий случай (как описано здесь наLinux съел мою оперативную память). Память будет освобождена всякий раз, когда это понадобится другому процессу.

РЕДАКТИРОВАТЬ: так как вы имеете в виду длительный процесс сервера, то ваша проблема заключается в использовании памяти, пока этот процесс все еще выполняется. Могу ли я предложитьValgrind как инструмент для обнаружения утечек памяти в вашем приложении, иRAII как метод кодирования для предотвращения утечек памяти. Обратите внимание, что использование памяти в Linux (и вообще!) Трудно измерить / интерпретировать, вывод таких инструментов, как ps и top, может быть обманчивым и неинтуитивным, например. согласноэтот ответ.

 user329624711 мар. 2014 г., 11:41
Я согласен, но мой процесс - процесс сервера и никогда не должен завершаться
 user329624711 мар. 2014 г., 12:54
@BasileStarynkevitch Конечно, но репутации не хватает: P
 Basile Starynkevitch11 мар. 2014 г., 13:56
@ user3296247: вы можете принять - даже с небольшой репутацией - какой-нибудь ответ (например, мой), если он подходит.
 Basile Starynkevitch11 мар. 2014 г., 12:20
@ user3296247: Тогдамой ответ Полезно.

виртуальная память) сММАП (2) (который используетсяmalloc или же::operator new, так далее...). Затем вы можете выпустить его позже сmunmap

посколькуmmap а такжеmunmapкак-то дорого,malloc (следовательно,::operator new который часто реализуется вышеmalloc) попробуйте повторно использовать ранееfree-d зоны памяти, так что не пытайтесь всегда освобождать память для ядра (ниже большого порога, возможно, 128 КБ или более).

КСТАТИ,Proc (5) предоставляет полезный интерфейс ядру для запросов. Для процесса pid 1234, вы могли быcat /proc/1234/maps чтобы показать свою карту памяти адресного пространства (внутри вашего процесса используйте/proc/self/maps)

Таким образом, вы могли бы код:

const size_t sz = 1048576;
/// allocating loop
for (i=0; i < 2000 ;i++ ) {
  void* ad = mmap(NULL, sz, PROT_READ|PROT_WRITE, 
                  MMAP_PRIVATE|MMAP_ANONYMOUS,
                  -1, (off_t)0);
  if (ad == MMAP_FAILED)
    { perror("mmap"); exit (EXIT_FAILURE); }
  p[i] = ad;
  memset (p[i], 0, sz); // actually uneeded
}
printf ("done allocating ... \n");
sleep(5);
// freeing loop
printf("Freeing\n");
for (i=0; i < 2000 ;i++ ) {
  if (munmap((void*)p[i], sz)) 
    { perror("munmap"); exit(EXIT_FAILURE); }
  p[i] = nullptr;
}

Заметить, чтоmmap сMAP_ANONYMOUS дает на успех обнуленную зону памяти, так что вам не нужноmemset очистить это.

В C ++ вы также можете определить свой собственныйoperator new (вызовmmap) а такжеoperator delete (вызовmunmap) если так хотел.

Читайте такжеРасширенное программирование в Linux.

Ваш ответ на вопрос