Потери динамически распределяемой памяти 


Мы поможем в написании ваших работ!



ЗНАЕТЕ ЛИ ВЫ?

Потери динамически распределяемой памяти



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

Общей причиной утечек памяти является переприсваивание динамических переменных без освобождения предыдущих. Простейшим случаем является следующий:

 

var IntPointer: ^Integer;

 

begin

New(IntPointer);

New(IntPointer);

end.

 

При первом вызове New в динамически распределяемой памяти выделяется 8 байт, и на них устанавливается указатель IntPointer. Второй вызов New выделяет другие 8 байт, и IntPointer устанавливается на них. Теперь у вас нет указателя, ссылающегося на первые 8 байт, поэтому вы не можете их освободить. В программе эти байты будут потеряны.

Естественно, утечка памяти может быть не такой очевидной, как в Примере 8.6. Выделение памяти почти никогда не происходит в последовательных операторах, но может выполняться в отдельных процедурах или далеко отстоящих друг от друга частях программы. В любом случае лучший способ отслеживания динамических переменных это установка их в nil при освобождении. Тогда при попытке распределить их снова вы можете убедиться что они имеют значение nil:

 

var IntPointer: ^Integer;

 

begin

New(IntPointer);

.

.

.

Dispose(IntPointer);

IntPointer:= nil;

.

.

.

if IntPointer = nil then New(IntPointer);

end.

 

Модули Turbo Pascal

В данной главе разъясняется, что такое модуль, как он используется, какие встроенные модули доступны пользователю, как писать собственные программные модули и как компилировать их.

 

Turbo Pascal обеспечивает вам доступ к большому числу встроенных констант, типов данных, переменных, процедур и функций. Некоторые из них специфичны для Turbo Pascal, другие специфичны для приложений Windows. Их количество велико, однако, в своей программе вы редко используете их все сразу. Поэтому они разделены на связанные группы, называемые модулями. В этом случае можно использовать только те модули, которые необходимы в программе.

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

Все описания внутри модуля связаны друг с другом. Например, модуль Strings содержит все описания, необходимые для подпрограмм работы со строками с завершающим нулем.

Turbo Pascal предоставляет пользователю ряд стандартных модулей, таких как System, Crt WinCrt и др. Они поддерживают наши программы Turbo Pascal и все записаны в одну из трех библиотек исполняющей системы (в зависимости от целевой платформы).

Ваша программа может использовать любую из процедур и функций в этих модулях, и вам не потребуется писать их заново.

Структура модуля

Структура модуля аналогична структуре программы, однако есть несколько существенных различий. Например, рассмотрим модуль:

 

unit <идентификатор>;

interface

uses <список модулей>; { Необязательный }

{ глобальные описания }

implementation

uses <список_модулей>; { Необязательный }

{ локальные описания }

{ реализация процедур и функций }

begin

{ код инициализации }

end.

 

Заголовок модуля начинается зарезервированным словом unit, за которым следует имя модуля (идентификатор) точно так же, как и в случае имени программы. Следующим элементом в модуле является ключевое слово interface. Оно обозначает начало интерфейсной секции модуля - части, доступной всем другим модулям или программам, в которых он используется.

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

Во-вторых, он может следовать немедленно за ключевым словом implementation. В этом случае все описания из этих модулей могут использоваться только в секции реализации.

Интерфейсная секция

Интерфейсная часть - "общедоступная" часть в модуле - начинается зарезервированным словом interface, следует сразу после заголовка модуля и заканчивается перед зарезервированным словом implementation. Интерфейс определяет, что является "видимым" (доступным) для любой программы (или модуля), использующей данный модуль.

В интерфейсной части (секции) модуля можно определять константы, типы данных, переменные, процедуры и функции. Как и в программе, они могут быть расположены в любом порядке, и секции могут встречаться повторно (например, ваша программа может содержать секцию var, за которой следует секция const, а затем другая секция var).

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

Секция реализации

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

Оператор uses может содержаться в секции реализации (implementation) и должен непосредственно следовать за ключевым словом implementation.

Обычные процедуры и функции, описанные в интерфейсной секции, то есть те из них, которые не являются подставляемыми (inline), должны повторно указываются в секции реализации. Заголовок procedure/function должен быть или идентичным тому, который указан в секции интерфейса, или иметь более краткую форму. В случае краткой формы наберите ключевое слово (procedure или function), а за ним укажите имя подпрограммы (идентификатор). Затем подпрограмма должна содержать все свои локальные описания (метки, константы, типы, переменные и вложенные процедуры и функции), за которыми должно находиться основное тело самой подпрограммы. Пусть в интерфейсной части указаны следующие описания:

 

procedure ISwap(var V1,V2: integer);

function IMax(V1,V2: integer): integer;

 

Тогда Секция реализации будет иметь следующий вид:

 

procedure ISwap;

var

Temp:= integer;

begin

Temp:= V1; V1:= V2; V2:= Temp

end; {конец процедуры Swap}

function IMax(V1,V2: integer): integer;

begin

if V1 > V2

then IMax:= V1

else IMax:= V2

end; { конец функции Max }

 

Подпрограммы, локальные для секции реализации (то есть не описанные в секции реализации), должны иметь полный (несокращенный) заголовок procedure/function.

Секция инициализации

Обычно вся секция реализации модуля заключена между зарезервированными словами implementation и end. Однако, если перед end поместить зарезервированное слово begin, а между ними - операторы, то получившийся составной оператор, очень похожий на основное тело программы, становится секцией инициализации модуля (initialization).

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

При выполнении программы, использующей некоторый модуль, секция инициализации этого модуля вызывается перед запуском основного тела программы. Если программа использует более одного модуля, то секции инициализации всех модулей вызываются (в порядке, указанном в операторе uses в программе) перед тем, как выполнить основное тело программы.

Как используются модули?

Модули, которые использует ваша программа, уже оттранслированы и хранятся, как машинный код, а не как исходный код на Паскале, поскольку они не являются включаемыми файлами. Даже интерфейсная секция хранится в специальном двоичном формате таблицы идентификаторов, используемом в Turbo Pascal. Более того, определенные стандартные модули хранятся в специальном файле (TURBO.TPL, TPW.TPL или TPP.TPL) и автоматически загружаются в память вместе с Turbo Pascal.

В результате использование одного или нескольких модулей очень незначительно увеличивает время компиляции вашей программы (обычно менее, чем на секунду).

Фактически, если модуль скомпилирован, его использование сохраняет вам время при перекомпиляции. Поскольку компилятор не перекомпилирует модуль, пока он не изменяется, использование модулей в программе ускорит процесс ее построения.

Как указывалось ранее, для использования специального модуля или набора модулей необходимо в начале программы поместить оператор uses, после которого указать список имен тех модулей, которые будут использоваться. Имена их должны разделяться запятыми:

 

program MyProg;

uses thisUnit, thatUnit, theOtherUnit;

 

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

Модули присоединяются к таблице идентификаторов в указанном порядке. Порядок модулей в операторе uses значения не имеет. Если модуль thisUnit использует thatUnit или наоборот, вы можете описать их в любом порядке, а компилятор определит, какой модуль нужно скомпоновать с программой MyProg первым. Фактически, если модуль thisUnit использует thatUnit, но MyProg не вызывает непосредственно ни одну из подпрограмм в модуле thatUnit, вы можете "скрыть" подпрограммы модуля thatUnit, опустив его в операторе uses:

 

unit thisUnit;

uses thatUnit;

.

.

.

program MyProg;

uses thisUnit, theOtherUnit;

.

.

.

 

В этом примере модуль thisUnit может вызывать любую подпрограмму модуля thatUnit, а программа MyProg может вызывать любую из подпрограмм модуля thisUnit или theOtherUnit. Однако, программа MyProg не может вызывать подпрограммы модуля thatUnit, поскольку thatUnit не указывается в операторе uses программы MyProg.

Если в программе не указан оператор uses, Turbo Pascal в любом случае присоединит стандартный модуль System. Этот модуль обеспечит выполнение некоторых стандартных подпрограмм Turbo Pascal, а также нескольких подпрограмм, специфических для Turbo Pascal.

Ссылки на описания модуля

Как только вы включили модуль в свою программу, все константы, типы данных, переменные, процедуры и функции, описанные в секции интерфейса этого модуля, становятся доступными для вашей программы. Например, допустим, имеется следующий модуль:

 

unit MyStuff;

interface

const

MyValue = 915;

type

MyStars = (Deneb,Antares,Betelgeuse);

var

MyWord: string[20];

 

procedure SetMyWord(Star: MyStars);

function TheAnswer: integer;

implementation

.

.

.

end.

 

Как можно видеть здесь в интерфейсной части модуля, та часть модуля, которая находится в интерфейсной секции, является видимой для вашей программы (и может ею использоваться). С учетом этого можно написать следующую программу:

 

program TestStuff;

uses MyStuff;

var

I: integer;

AStar: MyStars;

begin

Writeln(myValue);

AStar:= Deneb;

SetMyWord(AStar);

Writeln(MyWord);

I:= TheAnswer;

Writeln(I)

end.

 

После включения в программу оператора uses MyStuff вы можете ссылаться на все идентификаторы, описанные в интерфейсной секции модуля МyStuff (МyWord, МyValue и так далее). Однако, рассмотрим следующую ситуацию:

 

program TestStuff;

uses MyStuff;

const

MyValue = 22;

var

I: integer;

AStar: MyStars;

 

function TheAnswer: integer;

begin

TheAnswer:= 1

end;

 

begin

Writeln(myValue);

AStar:= Deneb;

SetMyWord(AStar);

Writeln(MyWord);

I:= TheAnswer;

Writeln(I)

end.

 

В этой программе переопределяются некоторые из идентификаторов, описанных в МyStuff. Будучи скомпилированной и выполненной, эта программа будет использовать собственные определения для МyValue и ТheAnswer, поскольку они были описаны позднее, чем определения в МyStuff.

Вероятно, вам интересно знать, каким образом в такой ситуации можно ссылаться на идентификаторы в МyStuff. Для этого необходимо перед каждым идентификатором помещать имя МyStuff с точкой (.). Например, рассмотрим еще одну версию этой программы:

 

program TestStuff;

uses MyStuff;

const

MyValue = 22;

var

I: integer;

AStar: MyStars;

 

function TheAnswer: integer;

begin

TheAnswer:= 1

end;

 

begin

Writeln(MyStuff.MyValue);

AStar:= Deneb;

SetMyWord(AStar);

Writeln(MyWord);

I:= MyStuff.TheAnswer

Writeln(I)

end.

 

Эта третья программа даст такие же ответы, что и первая, даже в том случае, если вы переопределите MyValue и TheAnswer. В действительности вы имели полное право написать первую программу следующим образом:

 

program TestStuff;

uses MyStuff;

var

I: integer;

AStar: MyStuff.MyStars;

 

begin

Writeln(MyStuff.MyValue);

AStar:= My.Stuff.Deneb;

MyStuff.SetMyWord(AStar);

Writeln(My.Stuff.MyWord);

I:= MyStuff.TheAnswer;

Writeln(I)

end.

 

Отметим, что имя модуля может предшествовать любому идентификатору: константе, типу данных, переменной или подпрограмме.



Поделиться:


Последнее изменение этой страницы: 2017-02-19; просмотров: 228; Нарушение авторского права страницы; Мы поможем в написании вашей работы!

infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 44.222.116.199 (0.065 с.)