On branch main
modified: src/ch05.md
This commit is contained in:
18
src/ch05.md
18
src/ch05.md
@@ -10,7 +10,7 @@
|
||||
(например, прочитать файл), может запросто использовать несколько сотен
|
||||
мегабайт памяти, сделать что-то потрясающее и далее выйти. По выходу
|
||||
операционная система освобождает все ресурсы (память, в частности),
|
||||
которые были исопльзованы программой, пока она выполнялась. Освобожденная
|
||||
которые были использованы программой, пока она выполнялась. Освобожденная
|
||||
память затем может быть отдана в пользование другим программам.
|
||||
|
||||
Однако, для программ, которые работают днями, месяцами и даже годами,
|
||||
@@ -18,7 +18,7 @@
|
||||
далеко не только какой-то отдельно взятой программе, но и другим,
|
||||
исполняющимся на этой же машине. То есть попросту невозможно ждать, пока
|
||||
какая-то программа не завершится и память станет доступной. Многие языки
|
||||
программиования имеют среду времени выполнения, в которую входит сборщик
|
||||
программирования имеют среду времени выполнения, в которую входит сборщик
|
||||
мусора - его первейшая задача как раз и есть отслеживание более не нужной
|
||||
памяти и её освобождение. Как уже пару раз упоминалось в предыдущих
|
||||
главах, в Zig нет сборщика мусора, поэтому его роль выполняет разработчик
|
||||
@@ -28,7 +28,7 @@
|
||||
область, где хранятся данные, не подлежащие модификации, то есть
|
||||
константы, включая строковые. Эти данные содержатся в исполнимом файле.
|
||||
Такие данные существуют (то есть занимают память) всё время выполнения
|
||||
программы, причём объём занимаемой имм памяти остаётся постоянным, он не
|
||||
программы, причём объём занимаемой ими памяти остаётся постоянным, он не
|
||||
может ни увеличиться, ни уменьшится. Но это не то, о чём нас следует
|
||||
беспокоиться, разве что общее количество таких данных сказывается на
|
||||
размере исполнимого файла.
|
||||
@@ -47,9 +47,9 @@
|
||||
переменная доступна только в той области видимости, где она была
|
||||
объявлена. В Zig области видимости это, по сути, блоки кода, окружённые
|
||||
фигурными скобками (`{ ... }`). Большинство переменных привязаны или к
|
||||
функции (включая её аргументы), или к управляющим констркуциям, таким
|
||||
функции (включая её аргументы), или к управляющим конструкциям, таким
|
||||
как, например, `if`. Однако, как мы видели, можно создавать любые блоки и
|
||||
тем самым, проивольные области видимости.
|
||||
тем самым, произвольные области видимости.
|
||||
|
||||
В предыдущей главе мы визуализировали содержимое памяти для функций
|
||||
`main` и `levelUp`, используя экземпляры переменной типа `User`:
|
||||
@@ -136,7 +136,7 @@ main: user -> ------------- (id: 1043368d0)
|
||||
В обычных программах стек довольно сильно заполнен, поскольку типичная
|
||||
программа использует множество библиотек, и как следствие глубина
|
||||
вложенности вызовов функций может быть достаточно большой. Обычно это не
|
||||
является проблемой, но иногда можно довести дело до переполения стека.
|
||||
является проблемой, но иногда можно довести дело до переполнения стека.
|
||||
Зачастую это случается с рекурсивными функциями, то есть функциями,
|
||||
вызывающими саму себя.
|
||||
|
||||
@@ -149,14 +149,14 @@ main: user -> ------------- (id: 1043368d0)
|
||||
|
||||
Выделение памяти на стеке и её освобождение это очень быстрые операции,
|
||||
поскольку это всего лишь декремент/инкремент указателя вершины стека
|
||||
(обычно стек "растёт" в сторону меньшмх адресов памяти).
|
||||
(обычно стек "растёт" в сторону меньших адресов памяти).
|
||||
|
||||
## "Висячие" указатели (dangling pointers)
|
||||
|
||||
Стек вызовов это замечательный механизм в силу его простоты и эффективности.
|
||||
Однако нас должно насторожить следующее обстоятельство: когда функция
|
||||
завершает работу, всё её локальные переменные как бы исчезают.
|
||||
Это, по идее, разумно, в конце концов, это же лоакльные переменные,
|
||||
Это, по идее, разумно, в конце концов, это же локальные переменные,
|
||||
они нужны только самой функции, но есть одно но. Рассмотрим следующий пример:
|
||||
|
||||
```zig
|
||||
@@ -217,7 +217,7 @@ User 16777216 has power of -1
|
||||
Почему так происходит? Дело в том, что функция `User.init` возвращает
|
||||
**адрес локальной переменной**, то есть `&user`. Это называется "висячий"
|
||||
указатель, источник многих проблем, вплоть до аварийного завершения или,
|
||||
по крайней мере, как мы только что виделм, явно некорректное поведения программы.
|
||||
по крайней мере, как мы только что видели, явно некорректное поведения программы.
|
||||
|
||||
Когда стековый кадр "уничтожается", всякие ссылки в ту область памяти,
|
||||
которую этот кадр занимал, становятся попросту бессмысленными. И что мы
|
||||
|
||||
Reference in New Issue
Block a user