Статическая локальная переменная, не занимающая физической памяти

#c #memory #static

#c #память #статическая

Вопрос:

Я создал следующие функции для проверки использования памяти статическими локальными переменными и ожидал, что массив займет примерно 5 МБ памяти, но когда я запустил его, использование физической памяти процессом составило всего 0,2 МБ и увеличилось, когда я фактически установил значение для каждого элемента в массиве.

Насколько я понимаю, массиву будет выделена память при первой его инициализации, независимо от значений элементов в нем. Поскольку я могу получить доступ к первому и последнему элементу массива, куда делась память между ними?

 void func() {
  static char a[5000000];
  a[0] = 'a';
  a[4999999] = 'a';
  cin >> a;
}

int main(int argc, char const *argv[]) {
  func();
  return 0;
}
  

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

1. Вероятно, ваша операционная система использует подкачку по требованию и не выделяет страницы процессу до тех пор, пока они фактически не будут использованы. Вы узнаете больше, когда пройдете курс для студентов колледжа по проектированию и внедрению операционной системы. Теперь попробуйте увеличить массив, затем выполните запись в различные части массива и посмотрите, каково в результате использование памяти.

2. Использование памяти увеличилось экспоненциально и составило половину ожидаемой памяти, когда я записал 5000 случайных частей массива, так что вы были определенно правы. Также спасибо за информацию о курсе.

3. Как вы измеряли память?

4. Я посмотрел процесс в диспетчере задач Windows. Процесс выполнялся в подсистеме Windows для Linux.

Ответ №1:

Это происходит из-за отложенного выделения памяти или заполнения нулем по требованию, как объяснено ниже.

Это объясняется в нулевой инициализации в cppreference:

Нулевая инициализация выполняется в следующих ситуациях:

1 Для каждой именованной переменной со статическим или потоковым локальным сроком хранения, которая не подлежит постоянной инициализации (начиная с C 14), перед любой другой инициализацией.

Итак, эта переменная соответствует требованиям. Что это значит нулевая инициализация:

Последствия нулевой инициализации следующие:

  • Если T — скалярный тип, начальным значением объекта является нулевая целочисленная константа, явно преобразованная в T.
  • […] Если T — тип массива, каждый элемент инициализируется нулем

В качестве оптимизации большинство современных систем даже не выделяют никакой памяти для инициализированных нулем глобальных / статических переменных, и именно поэтому размер массива не влияет на использование памяти. Вместо этого в исполняемом файле появляется пометка, которая гласит: «здесь должны быть нулевые значения», и ничего больше. При загрузке программы все адреса отображаются в небольшой общий блок физической памяти, доступный только для чтения, который содержит нули.

Несколько виртуальных адресов могут отображаться в одну и ту же память с помощью аппаратного обеспечения в процессоре, которое называется «Блок управления памятью» (MMU). Когда код пытается выполнить запись по адресу an в диапазоне, MMU уведомляет операционную систему (OS) о том, что кто-то записывает блок памяти, доступный только для чтения, и ОС выделяет память только тогда

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

1. Отличный пример того, почему попытка применить наивные низкоуровневые «физические» ожидания 1970-х годов к фрагменту исходного кода C в 2019 году в лучшем случае чревата осложнениями, а в худшем — совершенно бессмысленна. Просто кодируйте в соответствии со стандартами, если только вам не требуется сверхэффективность или вы пытаетесь отследить неприятную ошибку переполнения стека или что-то еще

2. @LightnessRacesinOrbit если я правильно помню, в Linux она есть с первого дня в начале 90-х. Windows-NT (предшественница Windows-10, начало-середина 90-х) также имела это с первого дня. IRIX, Solaris, AIX и другие unixen имели это с конца 80-х (или ранее). Это старая технология

3. Ну тогда довольно!