The website "dmilvdv.narod.ru." is not registered with uCoz.
If you are absolutely sure your website must be here,
please contact our Support Team.
If you were searching for something on the Internet and ended up here, try again:

About uCoz web-service

Community

Legal information

11.1 Пример

11.1 Пример

Предыдущая  Содержание  Следующая V*D*V

Все ресурсы, приобретённые программой, должны быть правильно возвращены для повторного использования. Динамическая память — ресурс, и выпускаемые версии программы конечно же должны быть проверены на утечки памяти. В качестве примера рассмотрим, что происходит, когда мы делаем синтаксическую ошибку при использовании калькулятора, разработанного в третьей и пятой главе:

 

$ value

(3 * 4) - -

bad factor: ’’ 0x0

 

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

NeXTSTEP предоставляет простое приложение MallocDebug, которое может использоваться, чтобы определить местоположение, по крайней мере, некоторых более серьёзных проблем. Если мы скомпонуем value с -lMalloc-Debug, стандартные версии malloc() и связанные с ней функции заменятся модулем, который сможет связаться с приложением MallocDebug. Запускаем MallocDebug после value, подключаем их друг к другу и нажимаем кнопку Leaks, как только получаем первое сообщение об ошибке. К сожалению, сообщение простое:

 

No nodes.

 

MallocDebug использует довольно наивный метод для проверки на утечки: оно имеет список всех выделенных областей памяти и просматривает слова в задаче клиента, чтобы увидеть, указывают ли они на выделенные области. Утечками памяти считаются только те области, на которые не указывает ни одно слово в задаче клиента. Для ввода

 

(3 * 4) - -

 

sum() получит первое поддерево, построенное product() прежде, чем factor() доберётся до конца строки ввода. Тем не менее, когда error() отсекает стек от factor() обратно к main(), адрес корня этого поддерева все ещё находится в локальной переменной result в sum() и по случайности не перезаписывается в longjmp(). Остающиеся узлы связаны с корневым, то есть с точки зрения MallocDebug до всех узлов всё ещё можно добраться. Однако, если мы введём другое выражение, старый стек перепишется, и MallocDebug найдет утечку.

value:

 

$ value

(3 * 4) - -

bad factor: ’’ 0x0

1 + 3

4

 

MallocDebug:

 

Zone:     Address:    Size:    Function:

 default  0x050ec35c     12    mkBin, new, product, sum,

                               factor, product, sum, stmt

 

Если value скомпилировано с отладочной информацией, мы можем запустить отладчик во втором окне и исследовать утечку:

 

$ gdb value

GDB is free software ...

(gdb) attach 746

Attaching program `value’, pid 746

0x5007be2 in read ()

(gdb) print * (struct Bin *) 0x050ec35c

Reading in symbols for mathlib.c...done.

$1 = {

  type = 0x8024,

  left = 0x50ec334,

  right = 0x50ec348

}

(gdb) print process(0x050ec35c)

Reading in symbols for value.c...done.

$3 = void

(gdb)

 

Отладчик GNU можно подключить к работающему процессу. С помощью print можно вывести на экран содержание узла с утечкой, если скопировать адрес из окна MallocDebug и подставить надлежащий тип: mkBin() вызывает malloc(), то есть мы должны были получить struct Bin. Как показывает вывод, print может даже вызвать метод, подобный process() в value, и показать результат. Вывод из process() появляется в окне, где выполняется value:

 

$ value

(3 * 4) - -

bad factor: ’’ 0x0

1 + 3

        4

        12

 

Утечка памяти жива и здорова.

 

Предыдущая  Содержание  Следующая