
Комментарии 5
Ох...
В общем, из статьи я вынес, что управлять памятью надо
с пристальным вниманием
с особой осторожностью
строго соблюдая правила безопасности памяти (чем бы это ни было)
с глубоким пониманием базовой структуры памяти (тоже не к этой статье)
с тщательным тестированием и проверкой кода (не знаю, на что)
Иначе возможны какие-то сбои и ошибки.
В целом – спасибо за статью. В процессе чтения, например, я заинтересовался, как вообще работает withUnsafeMutableBufferPointer, если Array в общем случае не обязательно хранит данные одним куском (в статье об этом не слова, хотя казалось бы...). Ну и заодно погуглил ещё несколько интересных вещей по ходу чтения.
Но...
Во-первых, скажите, пожалуйста, Вы случайно не пользовались какой-нибудь LLM при написании? ChatGPT, Yandex-что-то-там, LLAMA / Alpaca, вот это вот всё. Очень-очень много повторов, общих фраз.
подчеркнув глубокое погружение в низкоуровневые манипуляции с памятью
Насчёт глубокого погружения в низкоуровневые манипуляции я не уверен, но в самой статье я прямо плаваю :)
Во-вторых, осмысленность примеров под вопросом (об этом ниже), эффективность ручного управления не раскрыта, потенциальные проблемы не освещены.
Ну и в целом, я бы подчеркнул, что работа с указателями из Swift – это мазохизм и крайний случай. Если очень хочется, можно ещё рассмотреть вариант с Obj-C обёрткой вокруг C-библиотеки. Так по крайней мере со всеми этими withUnsafeMutablePointer не нужно иметь дело, и можно писать на нормальном C.
Однако это может стать проблематичным, если
swiftStringвыйдет за пределы области действия до того, какprintCStringзавершит выполнение
withCString вызывается синхронно, это понятно уже по декларации функции:
func withCString<Result>(_ body: (UnsafePointer<Int8>) throws -> Result) rethrows -> Resultbody не @escaping.
В этом примере класс
PixelBufferвыделяет память для экземпляровPixelв своем инициализаторе и освобождает ее в своем деинициализаторе. Этот подход уменьшает фрагментацию памяти за счет выделения непрерывного блока памяти для данных пикселей.
Я понимаю, что это пример, но, опять же, вы придумали ухудшенную версию ContinuousArray.
Например, вы можете реализовать собственный пул памяти для эффективного управления экземплярами класса
GameObject:
Опять же, зачем здесь вообще UnsafeMutablePointer? Вы всё равно возвращаете ранее использованный инстанс GameObject, так почему просто не сохранить их в массив? И все проблемы снимает как рукой, не надо "тщательно управлять" никакими жизненными циклами.
Включив такие методы, как подсчет ссылок в небезопасных контекстах, вы можете найти баланс между оптимизацией производительности и безопасностью памяти. Однако помните, что чем больше вы отклоняетесь от автоматического управления памятью Swift, тем большая ответственность за поддержание корректности и безопасности ложится на ваши плечи.
Вот, казалось бы, любопытная деталь, которая выглядит реально полезной, но что это за метод? Как его включить? Какие ещё "методы" можно включить? (написано "такие, как") Я предполагаю, что это флаг в target-е, наподобие zombie objects, так? Но в таком случае о каком балансе идёт речь? Оно может помочь обнаружить проблемы, какой вообще может быть баланс между оптимизацией и безопасностью памяти? Память или безопасна, или нет, она не может быть "немножко небезопасна, но зато у нас функция на полмиллисекунды быстрее работает". Точнее, может, конечно, но если пришла мысль написать такой код, надо или поспать, или идти в хаб "ненормальное программирование".
Реализовав связанный список с нуля, вы получите представление о тонкостях низкоуровневых манипуляций с памятью.
Так может быть вот это должно было быть статьёй?
небезопасный подход может обеспечить преимущества в производительности в определенных сценариях
Я вижу два практически идентичных фрагмента кода и общее утверждение, что один работает быстрее, чем другой. Где деньги, Лебовски? Неплохо бы в таком случае иметь хотя бы самые поверхностные тесты, которые это подтвердят. При этом вполне допустимо выбирать случаи, когда у ручного управления будут преимущества (хотя в идеале представить также и случаи, когда это не так). Но тут вообще никаких тестов нет.
Спасибо за такой развернутый комментарий!
Да, пользовался нейросетями и видимо стоило больше времени потратить на редакцию текста, учту при следующих статьях и спасибо за замечание.
В-принципе спасибо за все замечания, понял что сильно расфокусился на общую тему и надо было больше вглубь копнуть и что примеров не хватило.
Могу ошибаться, но сложилось впечатление, что сначала боремся за то, чтобы управление памятью было автоматическим и безопасным, потом натыкаемся на то, что в ряде случаев это дает просадку в производительности и пытаемся управлять памятью самостоятельно, но при этом боремся с автоматическим управлением чтобы оно нам кислород не перекрыло в самый неподходящий момент.
Для "динозавров", которые начинали с 80-90-х (и к коим смею себя причислять) на "чистом С", ручное управление памятью делается уже на подсознательном уровне. Это такая годами воспитанная дисциплина ума, не вызывающая каких-то проблем и/или дискомфорта. Скорее автоматическое управление порой вызывает некоторое раздражение - "оно чего-то там само делает, мной неконтролируемое" и к этому тоже нужно привыкать.
И, честно говоря, не возьмусь однозначно утверждать что лучше или хуже.
Написал маленькое, но важное дополнение к этой статье о выделении совместно используемой памяти
Расширенное управление памятью с помощью Unsafe Swift