В моей программе есть специальный распределитель, который получает память от ОС с помощью mmap(MAP_ANON | MAP_PRIVATE)
.Когда ему больше не нужна память, распределитель вызывает либо munmap
, либо madvise(MADV_FREE)
.MADV_FREE
сохраняет сопоставление, но сообщает ОС, что может отбрасывать физические страницы, связанные с сопоставлением.
Вызов MADV_FREE
на страницах, которые вам понадобятся снова, в конце концов, намного быстрее, чем вызовmunmap
и позже снова звоню mmap
.
Это почти идеально работает для меня.Единственная проблема заключается в том, что на MacOS MADV_FREE очень ленивы, чтобы избавиться от страниц, которые я попросил освободить.Фактически, он избавляется от них только тогда, когда возникает нагрузка на память от другого приложения.Пока MacOS не избавится от страниц, которые я освободил, моя программа все еще использует эту память;в Activity Monitor его столбец «Реальная память» не отражает освобожденную память.
Из-за этого мне сложно измерить, сколько памяти фактически использует моя программа.(Эта трудность в измерении RSS не позволяет нам разместить пользовательский распределитель на 10.5.)
Я мог бы выделить целую кучу памяти, чтобы заставить ОС освободить эти страницы, но в дополнение к длительномуЭто может иметь и другие побочные эффекты, например, выкладывание частей моей программы на диск.
На жаворонке я попытался выполнить команду purge
, но это никак не отразилось.
Как заставить MacOS очистить эти страницы MADV_FREE'd?Или, как я могу спросить MacOS, сколько страниц MADV_FREE у моего процесса в памяти?
Вот тестовая программа, если она помогает.В столбце «Реальная память» монитора активности отображается 512 МБ после перехода программы в спящий режим.На моем Linux-компьютере top показывает 256 МБ RSS, если нужно.
#include <sys/mman.h>
#include <stdio.h>
#include <unistd.h>
#define SIZE (512 * 1024 * 1024)
// We use MADV_FREE on Mac and MADV_DONTNEED on Linux.
#ifndef MADV_FREE
#define MADV_FREE MADV_DONTNEED
#endif
int main()
{
char *x = mmap(0, SIZE, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0);
// Touch each page we mmap'ed so it gets a physical page.
int i;
for (i = 0; i < SIZE; i += 1024) {
x[i] = i;
}
madvise(x, SIZE / 2, MADV_FREE);
fprintf(stderr, "Sleeping. Now check my RSS. Hopefully it's %dMB.\n", SIZE / (2 * 1024 * 1024));
sleep(1024);
return 0;
}