Книга "Современные операционные системы" от Tanenbaum, которая доступна онлайн здесь:
http://lovingod.host.sk/tanenbaum/Unix-Linux-Windows.html
Охватывает тему в глубину. (Глава 4 посвящена управлению памятью, а глава 4.8 - сегментации памяти). Краткая версия:
Было бы очень плохо, если бы несколько программ на вашем ПК могли обращаться к памяти друг друга. На самом деле, даже в одной программе, даже в одном потоке у вас есть несколько областей памяти, которые не должны влиять друг на друга. Обычно процесс имеет как минимум одну область памяти, называемую «стеком», и одну область, называемую «кучей» (обычно каждый процесс имеет одну кучу + один стек на поток. МОЖЕТ быть больше сегментов, но это зависит от реализации, и это не вопрос для объяснения здесь). В стеке сохраняются такие вещи, как аргументы вашей функции и ваши локальные переменные. В куче сохраняются переменные, размер и время жизни которых не может быть определено компилятором во время компиляции (это будет в Java все, что вы используете для оператора "new". Пример:
public void bar(String hi, int myInt)
{
String foo = new String("foobar");
}
в этом примере два объекта String: (на которые ссылаются "foo" и "hi"). Оба эти объекта находятся в куче (вы знаете это, потому что в какой-то момент обе строки были выделены с использованием «new». И в этом примере 3 значения находятся в стеке. Это будет значение «myInt», «hi» и "foo". Важно понимать, что "hi" и "foo" на самом деле не содержат строк напрямую, но вместо этого они содержат некоторый идентификатор, который говорит им, что они находятся в куче, где они могут найти строку. (Это не так просто чтобы объяснить использование java, потому что java много абстрагирует. В C "hi" и "foo" будет указателем, который на самом деле является просто целым числом, представляющим адрес в куче, где хранится фактическое значение).
Вы можете спросить себя, почему в любом случае есть стек и куча. Почему бы не поставить все на то же место. Объясняя, что, к сожалению, выходит за рамки этого ответа. Прочитайте книгу, которую я связал ;-). Короткая версия состоит в том, что стек и куча управляются по-разному, и разделение выполняется по причинам оптимизации.
Размер стека и кучи ограничен. (В Linux выполните ulimit -a
, и вы получите список, включающий «размер сегмента данных» (куча) и «размер стека» (ага ... stack: -)).).
Стек - это то, что только растет. Как массив, который становится все больше и больше, если вы добавляете все больше и больше данных. В конце концов вам не хватает места. В этом случае вы можете закончить запись в той области памяти, которая вам больше не принадлежит. И это было бы очень плохо. Таким образом, операционная система замечает это и останавливает программу, если это произойдет. В Linux вы получаете «Ошибка сегментации», а в Windows - «Нарушение прав доступа».
На других языках, таких как C, вам нужно управлять памятью вручную. Маленькая ошибка может легко заставить вас случайно записать в какое-то пространство, которое вам не принадлежит. В Java у вас есть «автоматическое управление памятью», что означает, что JVM делает все это за вас. Вам не нужно заботиться, и это берет на себя нагрузку как разработчик (обычно так и есть. Могу поспорить, что есть люди, которые не согласятся с «нагрузкой» ;-)). Это означает, что / j / невозможно / невозможно создавать ошибки сегментации с помощью Java. К сожалению, JVM не идеальна. Иногда в нем есть ошибки и ошибки. И тогда вы получите то, что получили.