Работа с памятью (обобщение)
Данная статья - скорее всего обобщение того, что упоминалось в прошлых
статьях относительно памяти, плюс к этому кое-что будет новым.
Память для
переменных, структур и прочего выделяется автоматически (заложено в возможностях
компилятора), и вручную. Первый способ не требует вмешательства программиста для
очистки памяти по окончанию использования. Второй способ этого требует. Однако
второй способ дает более гибкие возможности (вспоминаем связанные списки).
С
первым способом мы соприкасались постоянно, когда объявляли обычные переменные,
структуры, массивы. Компилятор сам автоматом выделял для их память, и освобождал
когда это требовалось. Второго способа мы лишь чуточку коснулись. Давайте в этой
статье его рассмотрим более подробно.
Выделение памяти с помощью Allocate
Функция Allocate позволяет выделять нужный размер памяти, при том надо
помнить что по окончанию необходимо ее освободить с помощью функции Deallocate.
Я бы вам посоветовал при написании кода, сразу по написании функции Allocate
ниже писать Deallocate для того, чтобы не забыть после.
Функция Allocate
имеет в себе всего один параметр: размер памяти в байтах.
Например:
'автоматическое выделение памяти Dim As Integer AAAA 'ручное выделение памяти Dim As Integer Ptr BBBB = Allocate(sizeof(Integer)) ' ------работа с переменной------- 'очистка выделенной памяти Deallocate(BBBB)
Ручное выделение памяти тем хорошо, что позволяет выделять одним разом нужное нестандартное кол-во памяти (под стандартными имелось ввиду: byte, integer и др.)
Выделение памяти с помощью СAllocate
Функция Callocate так же выделяет память, но в отличии от Allocate заполняет выделенную память нулями. Конечно же из-за этой способности скорость ее чуть ниже, но заполнение нулями часто бывает нужным. По окончании использования памяти, ее так же нужно освобождать с помощью Deallocate. У функции Callocate два параметра: первый кол-во участков памяти для выделения, второй размер в байтах(по умолчанию 1) для одного участка. По сути можно использовать как и Allocate выделяя заранее определенный размер, например так:
Dim As Integer Ptr BBBB = СAllocate(sizeof(Integer)) ' ------работа с переменной------- 'очистка выделенной памяти Deallocate(BBBB)
Или так:
Dim As Integer Ptr BBBB = СAllocate(35, Sizeof(Integer)) ' ------работа с переменной------- 'очистка выделенной памяти Deallocate(BBBB)
Во втором примере выделяется памяти 35*4=140 байт (на windows 32) или 35*8=280 байт (на windows 64), поскольку оператор Sizeof подсчитывает размер в байтах типа integer. А тип Integer, как нам известно, равен 4 или 8 байт в зависимости от разрядности операционной системы.
Переопределение памяти с помощью ReAllocate
Функция Reallocate позволяет изменить кол-во выделенной памяти, при этом сохраняя ее содержимое.
Dim As Byte Ptr a = Callocate(5),b Poke a+2,12 b = Reallocate(a,10) ? Peek(b+2) Deallocate(b) Sleep
В примере объявляем два указателя на область памяти, при том для одного
из них выделяем память. Далее с помощью Poke записываем значение по адресу a+2 .
Затем переопределяем память и присваиваем ее указателю b , при том память по
указателю a автоматически освобождается. Далее считываем то, что находится по
адресу b+2 по сути тоже смещение, что и a+2 И освобождаем память по указателю
b
Операторы Poke и Peek
Мы уже в одной из статей рассматривали вкратце эти операторы, но давайте чуть подробнее. Оператор Poke нужен для занесения значения по указанному адресу. Оператор Peek для получения значения из указанного адреса. А теперь рассмотрим их параметры:
Poke тип , адрес или смещение по адресу, значение
значение = Peek (тип , адрес или смещение по адресу )
Обратите внимание, оператор Poke пишется без скобок. Параметр тип является
необязательным. Если его не использовать, то по умолчанию тип равен Ubyte.
Смещение по адресу-это как раз и есть то, что мы использовали a+2. То есть
выделяя память, нам для отсчета дается адрес. Он имеет нулевое смещение a+0.
Таким образом, когда выделили 5 байт, его конечное смещение будет равно
a+4 Массивы построены как раз по этому принципу.
Оператор [ ]
Если уж я заговорил о смещении, то нельзя пропустить более удобное обращение к памяти с помощью оператора [ ] Используя этот оператор, обращение ведется почти как у массивов, разница лишь в скобках (у массивов круглые)
Dim As Byte Ptr a= Callocate(5) a[2]=12 ? a[2] Deallocate(a) Sleep
Удобно? Мне кажется да. Объяснять тут по моему просто нечего, все и так
прозрачно.
Оператор Clear
Данная функция заполняет определенным числом выделенную область. В примере ниже заполняется нулями вся выделенная область , но можно заполнять любую ее часть и не только нулями. Для того чтобы заполнить другим числом, достаточно во втором параметре функции Clear передать это число. Первый параметр этой функции смещение по адресу, третий кол-во в байтах для заполнения.
Dim As Byte Ptr a= Allocate(5) Clear(a[0],,4) ? a[0] Deallocate(a) Sleep
Мы уже немало говорили об операторах -> * и @ поэтому
останавливаться на них не буду, но думаю стоит остановиться на операторах New и
Delete
Операторы New и Delete
Оператор New выделяет память, одновременно подсчитывая размер типа для которого выделяется память. Оператор Delete ее освобождает. NEW имеет два параметра, записываемых чуть с непривычным синтаксисом. Первый - это тип , по которому оператор выделит память. Второй параметр - кол-во для выделения по данному типу.
Dim As Byte Ptr a= New Byte [5] a[2]=10 ? a[2] Delete [] a Sleep
Если во втором параметре оператора New не указывать кол-во, то по
умолчанию будет единица.
Вспоминается мне, в одной из статей я хотел
показать значимость деструктора. Как раз с помощью оператора Delete мы это и
сделаем . Для примера нам подойдет код связанного списка, только чуть дополним
его:
'---------Класс связанного списка------------ '-------------------------------------------- 'подкласс B Type B next_ As B Ptr =0 prev_ As B Ptr =0 value As Byte =0 End Type 'подкласс A (главный) Type A First_ As B Ptr =0 last_ As B Ptr =0 Declare Sub Add_last(As Byte) Declare Sub All() Declare Destructor() End Type ' метод добавления пункта в конец Sub A.Add_last(value_ As Byte) Dim temp As B Ptr = New B temp->value=value_ If first_=0 Then first_=temp Else last_->next_=temp temp->prev_=last_ Endif last_ = temp End Sub ' метод вывода всех значений Sub A.ALL() Dim temp As B Ptr =first_ Do ? temp->value temp=temp->next_ Loop While temp<>0 End Sub ' Удаление листа Destructor A() Dim temp As B Ptr Dim del As B Ptr =first_ Do temp=del->next_ Delete del del=temp Loop While temp<>0 End Destructor '----------конец класса------------- '----------------------------------- '------использование класса---------- Dim list As A Ptr = New A list->Add_last(10) list->Add_last(20) list->Add_last(30) list->All Delete list Sleep
Вы можете еще раз обратить внимание на оператор NEW . В этом примере New
подсчитывает размер занимаемой структуры A и выделяет память нужную для работы.
Оператор Delete при удалении объекта листа, сначала запускает деструктор,
удаляет все привязанные объекты, потом уже удаляет сам главный объект листа. И
конечно же при всем этом освобождается память.
Оператор FRE
Этот оператор показывает кол-во незанятой памяти.
Dim mem As Integer = Fre Print "Free memory:" Print Print mem; " bytes" Print mem \ 1024; " kilobytes" Print mem \ (1024 * 1024); " megabytes" Sleep
Данный пример взят из справки. В первой строчке переменной mem
присваивается кол-во свободной памяти в байтах. Далее выводится в консоль кол-во
памяти в байтах , килобайтах, мегабайтах.
Копирование и перемещение памяти
У языка FreeBasic как таковой нет простой встроенной возможности копировать и перемещать выделенные нестандартные области памяти. Я не беру в расчет копирование в цикле. Однако этого легко можно добиться с помощью API функций MoveMemory и CopyMemory. Функции используются совершенно одинаково, поэтому покажу на одном примере.
#INCLUDE "windows.bi" Dim As Byte Ptr a = Allocate(10), b = Allocate(10) Clear(a[0],20,10) CopyMemory(b,a,10) ? b[2] Sleep Deallocate(a):Deallocate(b)
Для того, чтобы использовать эти функции нужно подключить библиотеку, в
которой они находятся с помощью заголовочного файла "windows.bi"
У обоих функций одинаковые параметры:
- буфер куда копировать или перемещать
- буфер откуда копировать или перемещать
- размер для копирования или перемещения в байтах
В примере мы выделили память для двух блоков памяти. Далее с помощью Clear заполнили один из буферов значениями 20. Потом скопировали содержимое буфера a в буфер b. Затем вывели значение одной из ячеек буфера b. И освободили выделенную память.
Пожалуй это все, всего доброго!
содержание | назад | вперед