#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. Ну тогда довольно!