Предположим, я объявляю глобальный массив в куче с размером, превышающим предел кучи. Конечно, ошибка сегментации будет выброшена. У меня вопрос: что происходит, когда мы это делаем? Запишут ли лишние целые числа некоторые части нашей компьютерной системы?

c
-1
jordan.goe 10 Ноя 2019 в 02:05
1
Нет. Это причина ошибок сегментации: операционная система защищает другие процессы.
 – 
mnistic
10 Ноя 2019 в 02:10
1
Когда у вас заканчивается место в куче, вы получаете NULL возврат от malloc и realloc. Вы не получите ошибок сегментации. Ошибки сегментации указывают на неправильное использование указателя.
 – 
Steve Summit
10 Ноя 2019 в 02:39
При попытке записи в память, которой вы не владеете, вы получаете ошибку сегментации вместо успешной записи в память, которой вы не владеете. Так что нет, вам не удастся «перезаписать некоторые части в нашей компьютерной системе».
 – 
Steve Summit
10 Ноя 2019 в 02:41
Предел кучи - это, по сути, предел виртуального адресного пространства в современных операционных системах, если операционная система не применяет ограничение к процессу
 – 
marko
10 Ноя 2019 в 02:52
2
Невозможно объявить какой-либо глобальный массив в куче. Куча - это (неофициальное и не совсем правильное название) область памяти, которая выделяется и освобождается динамически (например, с использованием malloc() и free()). Так что утверждение «конечно, будет произведена ошибка сегментации» - это фикция. Ошибка сегментации возникает, когда операционная система (unix) обнаруживает процесс, обращающийся к нераспределенной памяти, и отправляет сигнал для принудительного завершения процесса. ОС защищает память, чтобы предотвратить доступ процесса к памяти, которой он не должен.
 – 
Peter
10 Ноя 2019 в 03:20

2 ответа

Это зависит от используемой вами операционной системы (если таковая имеется).

Системы, которые предоставляют абстракцию обрабатывают виртуальную машину, то есть любой вариант * nix , Windows, некоторые ОСРВ, например QNX

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

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

Превышение конца блока кучи - это неопределенное поведение в C. Это может вызвать исключение или любое другое неожиданное последствие. Спорный вопрос, переполнили ли вы всю кучу на этом этапе.

Все эти операционные системы предотвращают удаление процесса из системной памяти.

Системы с чистым металлом, некоторые встроенные операционные системы

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

1
marko 10 Ноя 2019 в 15:18
Нет. Пейджинг не имеет значения. если вы установите размер кучи на N байтов, если вы попытаетесь выделить больше, чем она свободна (т. е. N за вычетом уже выделенной памяти), функция распределения вернет NULL. Нет ошибок. /
 – 
P__J__
10 Ноя 2019 в 02:54
@P__J__: ограничение кучи - это, по сути, ограничение виртуального адресного пространства во всех современных операционных системах - вероятно, оно меньше 2 ^ 64 в большинстве 64-битных систем, но все же значительно велико. Вполне возможно, что в стандартной C-библиотеке применяется ограничение, или процесс будет работать с ограничением максимального виртуального адресного пространства. Во встроенных системах наличие malloc() return NULL определенно возможно. В операционных системах общего назначения вам придется очень постараться, чтобы это произошло.
 – 
marko
10 Ноя 2019 в 03:01
2
Это может быть, но это не обязательно . Кстати, при разработке uC мы стараемся избегать каких-либо динамических распределений. Некоторые стандарты программирования полностью запрещают это, так что этот случай намного менее интересен.
 – 
P__J__
10 Ноя 2019 в 03:06
Конечно - я думаю, что мой ответ выше подтвердил это. Проблема встроенных систем заключается в том, что реализации кучи общего назначения редко предлагают O(1) производительность выделения и освобождения памяти и потенциально могут вызвать инверсию приоритетов. Я сильно подозреваю, что OP не использует RTOS или систему без ОС.
 – 
marko
10 Ноя 2019 в 03:15
Это не главная проблема. Основная проблема - фрагментация кучи.
 – 
P__J__
10 Ноя 2019 в 03:19

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

Вы не можете объявить глобальный массив в куче, так как у вас нет доступа к этой памяти во время компиляции.

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

Память куча может быть выделена только динамически во время выполнения с помощью функций семейства malloc.

int a[500]; // 'a' is a static storage duration object

int foo()
{
   int b[500]; //'b' is an automatic storage duration object (most implementations use stack for it)
   static int c[500]; // 'c' is a static storage duration object
   int *d; //'d' is an automatic storage duration pointer (most implementations use 

   d = malloc(1000); // 'd' references the 1000 byte memory area allocated on the heap
}

Если вы попытаетесь выделить больше памяти, чем доступно, функция распределения вернет NULL, но не завершится ошибкой. Если вы попытаетесь получить доступ к памяти, которая не принадлежит объекту - это неопределенное поведение, которое потенциально может привести к ошибке сегментации.

0
P__J__ 10 Ноя 2019 в 03:14