Категория > Новости > Безопасность памяти. Учимся использовать указатели и линейные типы - «Новости»
Безопасность памяти. Учимся использовать указатели и линейные типы - «Новости»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);
Перейти обратно к новости |