У меня есть сервер с 2 процессорами и 64 ГБ оперативной памяти, 32 ГБ на процессор.
Я знаю, что каждый процессор имеет свою часть оперативной памяти, давайте назовем их RAM1 и RAM2. Я хотел бы, чтобы моя программа знала, в какой оперативной памяти (RAM1 или RAM2) она распределяет свои данные.
Я пытался проверить значения указателей:
// put the thread at i-th CPU, using pthread_setaffinity_np
TData *a = new TData[N];
...
cout << "CPU = " << i << " adress = " << a << endl;
но вывод выглядит случайным. Я полагаю, это потому, что адреса являются виртуальными. Есть ли соответствие между адресами виртуальной памяти и частью ОЗУ?
Как проверить, в какой оперативной памяти расположен мой массив «a»?
На ваш вопрос ответили Вот. Я хотел бы только добавить несколько комментариев.
Обратите внимание, что вызов new []
на самом деле не выделяет физическую память. В современных операционных системах это только приводит к анонимному отображению памяти. Анонимные сопоставления не соответствуют файлам в файловой системе, а скорее поддерживаются подкачкой (если есть). Первоначально вся область указывает на доступную только для чтения страницу в ядре, которая содержит все нули. Только когда вы действительно записываете во вновь выделенную память, устанавливается новая страница памяти, которая заменяет нулевую страницу для диапазона страниц, на который падает доступный адрес. Вот почему мы говорим, что нулевая страница копируется при записи (или CoW) и отображается в виртуальном адресном пространстве процесса. Политика по умолчанию заключается в том, чтобы попытаться разместить новую страницу на том же узле NUMA, где выполняется поток, который получил доступ к области памяти. Это называется политикой NUMA «первого прикосновения». Если на этом узле NUMA недостаточно памяти, страница выделяется на другом узле с достаточным объемом свободной памяти. Кроме того, небольшие выделения могут оказаться внутри большей области (называемой ареной), управляемой распределителем памяти библиотеки C malloc()
(оператор C ++ new []
звонки malloc()
для того, чтобы сделать фактическое распределение памяти). В этом случае страницы могут уже присутствовать в физической памяти даже до того, как вы запишете во вновь выделенную память.
У Linux есть неприятная привычка не сохранять ассоциацию областей памяти NUMA при ее перестановке. То есть, если страница была размещена на узле NUMA 0, затем выгружена и снова заменена, нет никакой гарантии, что страница не будет размещена на узле NUMA 1. Это ставит вопрос «где выделена моя память» немного сложно, так как последовательный обмен, сопровождаемый заменой, может легко аннулировать результат, который вы получаете от move_pages()
доли секунды назад. Поэтому вопрос имеет смысл только в следующих двух особых случаях:
mlock(2)
системный вызов, чтобы сказать ОС не менять конкретный диапазон из виртуального адресного пространства процесса;Память виртуализируется через MMU, поэтому каждый процесс видит пространство памяти размером 2 ^ 64. В этом процессе адреса являются виртуальными, поэтому они не имеют смысла. Нет никакого соответствия между виртуальными адресами (видимыми приложением) и физическими адресами (в оперативной памяти) на уровне процесса.
Ваше приложение должно запросить операционную систему, чтобы узнать, какие физические адреса оно постоянно использует.