Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Скачиваний:
21
Добавлен:
25.04.2015
Размер:
7.46 Кб
Скачать
{$mode objfpc}

var
p, q: ^integer;
t: ^byte;
u: pointer;

begin
new(p);
q := p + 1;
u := q;
t := u;
t += 4;
u := t;
q := u;
writeln(cardinal(p));
writeln(cardinal(q));
writeln(cardinal(q-p));
dispose(p);
end.

{type
tarr = array [1..100] of integer;

var
p: ^tarr;

begin
new(p);
p^[1] := 13;
writeln(p^[1]);

dispose(p);
end.}

{var
i, j: integer; //лежат в статической памяти
p: ^integer;

procedure f(x: integer);
var i: integer;
begin
writeln('local i = ', cardinal(@i));
writeln('local x = ', cardinal(@x));
end;

begin
writeln('global i = ', cardinal(@i));
writeln('global j = ', cardinal(@j));

new(p);
writeln('dynamic p = ', cardinal(p));
new(p);
writeln('dynamic p = ', cardinal(p));

writeln('global p = ', cardinal(@p));

f(1);
writeln('function f =', cardinal(@f));
end.
}
{
Работа с динамической памятью
--------------------------------------------------------------------------------
Иерархия памяти: регистры, кэш, оперативная память, внешние накопители,...
Все переменные хранятся в оперативной памяти.
Комплятор для оптимизации может поместить некоторые переменные в регистры.
Некоторые переменные на самом деле могут находиться в кэше.
Но все эти механизмы прозрачны для программиста.
С точки зрения программиста все переменные лежат в оперативной памяти.

Данные в программе могут храниться одним из трёх способов:
1. В статической памяти (глобальные переменные).
2. Стек (агрументы функций, локальные переменные функций, адреса возврата).
3. В динамической памяти (динамические переменные, динамические массивы, строки).

Ручное управление памятью.
Операционная система. В ней работают процессы.
Процесс - это программа.
Процессы просят память у ОС с помощью системных вызовов.
ОС выделяет память блоками.
Процессы могут возвращать ОС блоки памяти.

В ЯП для ручного управления памятью должны быть функции:
- Выделить память.
- Освободить память.
Память выделяется кусками (не те блоки, которые возвращает ОС).
Измнеть размер куска в общем случае нельзя.
Вместо этого можно выделить новый (больший) кусок памяти, скопивать в него данные из старого куска,
и освободить память, занимаемую старым куском.

Когда процесс заканчивает работу, все занимаемые им блоки памяти освободжаются.

Проблема 1. Возможны утечки памяти.
- выделяем кусок памяти.
- открываем файл.
- если файл не отркылся - выходим из текущей функции
- освобождаем выделенный кусок

Проблема 2. Висячие ссылки.
Висячая ссылка (висячий указатель) - это указатель на блок памяти, которая уже освобождена.
Осложнена отладка висячих указателей, т.к. обращение к уже особождённой памяти не всегда приводит к ошибке.

Выделение и освобождение памяти происходит не прямыми системными вызовами (хотя это возможно).
Программист хочет выделять память блока разного размера, а ОС выдаёт блоки одного размера.
Эти проблемы решает менеджер памяти. В ЯП с ручным управлением памятью менеджер памяти
реализован в функциях выделения и освобождения памяти.

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

Функции выделения/освобождения памяти в ЯП Паскаль.
Способ 1.

new(var p: pointer); - выделяет объем памяти в соответствии с типом указателя.
Т.е., если указатель нетипизированный, то компилятор выдаст ошибку.
После вызова в переменной p находится указатель на начало выделенного блока памяти.
Если память выделить не удалось - p = nil.

dispose(p: pointer); - сразу после вызова p становится висячей ссылкой.

Способ 2. Более низкоуровневый.

getmem(out p: pointer; sz: integer) - указатель может быть нетипизированным,
потому что размер выделяемого блока памяти передаётся в качестве аргумента.

freemem(p: pointer; sz: integer) - освобождение памяти.

Не смешивать new и freemem, getmem и dispose. Потому что менеджер памяти на это не рассчитан.

Операторы для работы с указателями
^ - разыменование (унарный оператор)
@ - взятие адреса (унарный оператор)
[] - взять элемент с заданным индексом
p[0] ~ p^
p[1] ~ (p+1)^
p^[1] = сначала разыменовать, а потом обратиться к ячейке массива (для указателей на массив)
Арифметка на указателях
p,q - указатель на тип t
x - число
p + x - указатель на байт памяти, сдвинутый от p вперёд на x*sizeof(t)
p - x
q - p - количество элментов типа t, находящихся между p и q.
}

Соседние файлы в папке 11_dynamic_memory