Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Скачиваний:
115
Добавлен:
02.05.2014
Размер:
93.7 Кб
Скачать

1. Мусор.

Есть два указателя р1 и р2 типа Т.

р1 р1 := new T;

р2 р2 := new T;

p1 p2 p1 := p2;

Так как доступ к объекту из динамической памяти возможен только через указатель, а у нас информация об указателе р2 уже потеряна, то мы не можем указать менеджеру динамической памяти на то, что этот объект нам больше не нужен. Сам он до этого никогда не дойдет. В памяти остается мусор.

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

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

2. «Висячие» ссылки.

Это обращение к памяти, которая уже освобождена.

Есть р1 и р1 – указатели.

р1 р2 Дальше делаем UNCHECKED_DEALLOCATION (p1);

р1 = NULL;

И получаем:

р1 р2

И получается, что у нас р2 – «висячая» ссылка. Хорошо, если такого рода операции написаны в программе рядом, а то бывает, что в самом начале сделаем присваивание, потом удалим и забудем, что делали присваивание и удаление. Позже напишем что-то типа р.i = ….., где i поле записи.

(В Аде синтаксис разыменования немного похож на Обероновский. Если пишем p.i, то ссылаемся на конкретное поле записи, а если хотим сослаться на всю запись целиком, например, передать в качестве параметра функции, то пишем p.all.)

Что произойдет в этот момент? Это зависит от менеджера динамической памяти. Самое противное с точки зрения программиста то, что именно в данный момент ничего не произойдет, но в некоторые моменты программа будет давать сбой, причем вычислить внешние условия, при которых это случается, будет практически невозможно. Или при переносе с одной системы на другую это обнаружится. В одной системе программа работала, а в другой – нет.

while (p != NULL) {

free (p);

менеджер памяти освободил память, но ничего с ней не сделал. Что-то может произойти, если кто-то другой попросит malloc, и менеджер памяти отдаст ему этот кусок.

p = p -> next;

}

Будет ли работать такой фрагмент программы? Это типичная ошибка. Мы сначала освобождаем р, а потом ссылаемся на освобожденный участок памяти. Если написать простое консольное приложение на Visual C++, то программа прекрасно будет работать, потому что она однопоточная. А если программа многопоточная, менеджер одновременно работает сразу со всеми потоками (потоки отличаются от процессов тем, что все они работают в одном адресном пространстве). Ваш поток прерывается, другой поток запрашивает память, менеджер динамической памяти отдает ему именно этот кусок, и Вы его дальше начинаете портить. Что будет дальше, кто и в какой момент слетит, предугадать очень сложно. Это первая проблема.

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

На одной системе программа работает, на другой – нет, а самое интересное, когда мы найдем соответствующую ошибку?!

Системы с автоматической сборкой мусора эти проблемы решают.

13

Соседние файлы в папке Лекции по программированию на ЯВУ