Категория > Новости > Безопасность памяти. Учимся использовать указатели и линейные типы - «Новости»
Безопасность памяти. Учимся использовать указатели и линейные типы - «Новости»17-11-2020, 00:01. Автор: Ogden |
|
предыдущей статьей, где я рассматривал механизмы сборки мусора и их особенности. Как мы видели на примере с использованием Boehm GC в C, сборка мусора сама по себе решает только проблему с утечками памяти. Безопасность памяти обеспечивают уже свойства самого языка. Ассоциация между сборкой мусора и безопасностью памяти возникает от того, что многие популярные прикладные языки не разрешают ручное управление памятью и адресную арифметику вовсе, — в этих условиях у пользователя просто нет возможности выполнить небезопасную операцию. Однако и возможности освободить память тоже нет, поэтому нужен какой-то механизм автоматического управления, и сборка мусора — самый популярный. Самый популярный не значит единственный и универсальный. Первая и главная проблема языков с принудительной сборкой мусора — на них можно писать только программы, которые выполняются в пространстве пользователя. Ядру операционной системы или прошивке микроконтроллера не на кого положиться, они вынуждены управлять памятью самостоятельно, а значит, и язык должен поддерживать указатели и адресную арифметику. Вторая проблема — потеря производительности и предсказуемости времени выполнения. Классические однопоточные сборщики мусора создают паузы в выполнении программы, которые могут быть заметны пользователю. При использовании многопоточных алгоритмов и верной настройке таймеров под задачи конкретного приложения можно свести паузы к минимуму, но свести затраты ресурсов на сборку мусора к нулю невозможно. Вполне логично, что разработчики языков ищут альтернативные и промежуточные варианты. Давай посмотрим, какими способами разные языки пытаются обеспечить безопасность памяти. Строгая типизация указателейПроблемы с безопасностью памяти в C возникают в первую очередь из-за отсутствия строгой типизации. Функция Ну и самая классическая ошибка, конечно, — случайное обращение к нулевому указателю. #include <stdio.h>void main(void) { char* str = NULL; printf("%sn", str);}
Более современные языки для системного программирования относятся к этому вопросу более ответственно. Например, в аде нетипизированные указатели — особый и редкий случай. Обычные указатели всегда типизированные. Вместо Таким способом запросить или освободить неверный объем памяти гораздо сложнее. Использование после освобождения, впрочем, также будет обнаружено только во время выполнения программы. infoУказатели в аде называются access types. Например, Для демонстрации сохраним следующий код в файл with Ada.Unchecked_Deallocation;procedure Access_Example is type Int_Ptr is access Integer; -- Специализация дженерика РїРѕРґ Int_Ptr procedure Free_Integer is new Ada.Unchecked_Deallocation(Object => Integer, Name => Int_Ptr); P : Int_Ptr; I : Integer;begin -- Запрашиваем память РїРѕРґ целое число СЃ помощью new -- Рё сохраняем туда значение 42 P := new Integer'(42); -- Освобождаем память, теперь P = null Free_Integer(P); -- Пробуем получить значение РїРѕ указателю I := P.all;end Access_Example;Теперь скомпилируем с помощью GNAT и запустим.
Как видим, тип указателя Однако начиная с Ada 2005 поддерживается и проверка, что указатель ненулевой. Для этого нужно исправить
На практике от такого типа мало пользы, поскольку его память невозможно освободить. По этой причине опцию type Int_Ptr is access Integer;subtype Initialized_Int_Ptr is not null Int_Ptr;procedure Some_Proc(Arg: Initialized_Int_Ptr);Перейти обратно к новости |