Pull to refresh

Comments 11

Отличная статья, довольно подробно расписано. Я Android разработчик, но ознакомился для общего развития, как устроено у вас. Можно обновлять резюме :D

«По умолчанию пул освобождает эти объекты в конце RunLoop'a выполняемого потока, чего более чем достаточно, чтобы покрыть все случаи.»
По умолчанию, пул не освобождает эти объекты в конце RunLoop'а, а уменьшает счётчик ссылкок на 1.

Функция "release" переводиться как "освободить", и уменьшает счетчик ссылок на 1. Так что формулировка вполне корректная.

Информативная статья, как и телеграм-канал. Спасибо, что предоставляете возможность погрузиться в iOS-разработку

UFO landed and left these words here

В этом-то и беда данной статьи - проскакать по верхам без понимания сути - получатся мемы типа байткода или даже целого абзаца:

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

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

Успехов.

Пропущены слова в абзаце про СТЕК: Если размер вашего value type может быть определен во время компиляции или если ваш не содержит рекурсию на себя или не находится в ссылочном типе, тогда потребуется выделение стека.

Ваш не содержит рекурсию?

А так спасибо за статью.

Уже идет работа по move-only типам (в виде атрибутов для локальных переменных, аргументов функций и возвратов, полей классов), правда непонятно как это будет работать value типами у которых внутреннее хранилище реализовано с использованием класса и будет ли deinit у структур.

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

«Существует ограничение в том, что данные, которые предполагается хранить в стеке, обязаны быть конечными и статичными — их размер должен быть известен ещё на этапе компиляции»

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

Второй способ — с помощью функции alloca, которая выделяет память не в куче, а в стеке. В этом случае размер стекового кадра не только не статичен, но ещё и неизвестен во время компиляции. Правда, пользоваться функцией не всегда удобно. Если, допустим, надо создать в стеке какой-то объект, то сперва надо вычислить его размер и только потом вызвать alloca. Такое преодоление пропасти в два прыжка мешает написать конструктор объекта, который бы сделал это всё сразу.

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

Есть ещё одна интересный вопрос — а как удлинить массив в стеке? На первый взгляд проблема нерешаема: массив в архитектуре x86 растёт в сторону старших адресов, а стек — наоборот, в сторону младших адресов. Тогда надо «перевернуть» массив, чтобы он рос в обратном направлении! По факту элемент массива с индексом [n] станет на самом деле элементом с индексом [-n]. Этот массив может расти при условии, что он находится на вершине стека и за ним ничего нет. Если наращиванием массива будет заниматься какая-то вызываемая функция, то возникнет угроза перекрытия растущего массива и локальных данных этой функции. Так что для аккуратного программирования тут лучше опять использовать модель памяти с двумя стеками. Подробности — здесь. Ещё надо заметить, что массив — не единственный агрегатный тип данных, который может расти в стеке. Расти, наверное, могут многие, если не все — при условии правильного исполнения. Массив же выбран в качестве примера по причине его простоты.

Всё вышеперечисленное подчиняется дисциплине LIFO: буква «L» в этой аббревиатуре означает «Last», «последний». То есть и резервирование памяти с помощью alloca, и создание нового объекта конструктором в двухстековой модели, и удлинение массива — всё это делается в памяти, лежащей ниже последнего («Last») элемента стека.

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



Sign up to leave a comment.

Articles