|
|
|
| |
Главная С++ (часть 4) Однопоточный сборщик мусора
Однопоточный сборщик мусора |
#include <iostream> #include <list> #include <typeinfo> #include <cstdlib> using namespace std; // Для наблюдения за работой сборщика мусора определите DISPLAY. // #define DISPLAY // исключение генерируется при попытке использовать объект // Iter, выходящий за пределы диапазона // базового объекта. // class OutOfRangeExc { // Добавьте функциональные возможности, если они необходимы // для вашего приложения. }; // Класс-итератор (iterator-like) для циклического перемещения //в массивах, на которые указывают указатели GCPtr. Указатели Iter //** не участвуют **в сборе мусора и не влияют на него. // Следовательно, указание с помощью Iter //на какой-либо объект не препятствует // освобождению отведенной объекту памяти. // template <class Т> class Iter { Т *ptr; // значение текущего указателя Т *end; // указывает на элемент, следующий за последним элементом Т *begin; // указывает на начало распределенного массива unsigned length;// длина массива public: Iter() { ptr = end = begin = NULL; length = 0; } Iter(T *pf T *first, T *last) { Ptr = p; end = last; begin = first; length = lasc - first; } // Возвращает длину последовательности, на которую // этот Iter указывает. unsigned size() { return length; } // Возвращает значение, на которое указывает ptr. //Не разрешает выход за пределы диапазона. Т &operator*() { if{ (ptr >= end) 11 (ptr < begin) ) throw OutOfRangeExc(); return *ptr; } // Возвращает адрес, содержащийся в ptr. // Препятствует выходу за пределы диапазона. Т *operator->() { if( (ptr >= end) || (ptr < begin) ) throw OutOfRangeExc () ; return ptr; } // Префикс ++. Iter operator++() { ptr++; return *this; } // Префикс —. Iter operator—() { ptr—; return *this; } // Постфикс ++. Iter operator++(int notused) { T *tmp = ptr; ptr++; return Iter<T>(tmp, begin, end); } // Постфикс —. Iter operator—(int notused) { T *tmp = ptr; ptr—; return Iter<T>(tmp, begin, end); } // Возвращает ссылку на объект //с заданным индексом. Не разрешает выход //за пределы диапазона. Т &operator[](int i) { if( (i < 0) || (i >= (end-begin)) ) throw OutOfRangeExc () ;* return ptr[i]; } // Определяет операции отношения, bool operator==(Iter op2) { return ptr == op2.ptr; } bool operator!=(Iter op2) { return ptr != op2.ptr; } bool operator<(Iter op2) { return ptr < op2.ptr; } bool operacor<=(Iter op2) { return ptr <= op2.ptr; } bool operator>(Iter op2) { return ptr > op2.ptr; } bool operator>=(Iter op2) { return per >= op2.ptr; } II Вычитает целое из Iter. Iter operator-(int n) { ptr -= n; return *this; } // Прибавляет целое к Iter. Iter operator+(int n) { ptr += n; return *this; } // Возвращает число элементов между двумя указателями Iter, int operator-(Iter<Т> &itr2) { return ptr - itr2.ptr; } }; // Этот-класс определяет элемент, который запоминается //в информационном списке сбора мусора. // template <class Т> class GClnfo { public: unsigned refcount; // текущее число ссылок T *memPtr; // указатель на выделенную память /* isArray равен true, если memPtr указывает на размещенный массив. В противном случае false. */ bool isArray; // true, если указание на массив /* Если memPtr указывает на размещенный массив, то arraySize содержит его размер */ unsigned arraySize; // длина или размер массива // Здесь mPtr указывает на выделенную память. // Если это массив, в size определяет // размер массива. GCInfo(T *mPtr, unsigned size=0) { refcount = 1; memPtr = mPtr; if(size != 0) isArray = true; else isArray = false; arraySize = size; } }; // Перегруженная операция == позволяет сравнивать объекты GCInfo. // Это необходимо для класса list библиотеки STL. template <class Т> bool operator==(const GCInfo<T> &obl, const GCInfo<T> &ob2) { return (obl.memPtr == ob2.memPtr); ) // GCPtr реализует тип указателя, применяющегося // для сбора мусора и освобождающего неиспользуемую память. // GCPtr должен использоваться только для указания на память, // которая выделяется динамически с помощью new. // Если применяется для ссылки на массив, // определяет размер массива. // template <class Т, int size=0> class GCPtr { // gelist поддерживает список сбора мусора, static list<GCInfo<T> > gclist; // addr указывает на выделенную память,.на которую // этот указатель GCPtr ссылается в данный момент. Т *addr; /* isArray равен true, если этот GCPtr указывает на размещенный массив. В противном случае равен false. */ bool isArray; // Равен true, если указание на массив. II Если этот GCPtr указывает на размещенный динамически // массив, arraySize содержит размер массива, unsigned arraySize; // размер массива static bool first; // Равен true, когда создается первый GCPtr. // Возвращает iterator для указателя info в списке gclist. typename list<GCInfo<T> >::iterator findPtrInfo(T *pcr); public: // Определяет тип итератора для GCPtr<Т>. typedef Iter<T> GCiterator; // Конструктор для инициализированных и неинициализированных // объектов. GCPtr(Т *t=NULL) { // Регистрирует shutdown() как функцию завершения, if(first) atexit(shutdown); first = false; list<GCInfo<T> >::iterator p; p = findPtrlnfo(t); // Если t уже есть в списке gclist, // увеличивает его счетчик ссылок. // В противном случае добавляет его в список. if(p != gclist.end()) p->refcount++; // увеличение счетчика ссылок else ( // Создает и запоминает новый элемент. GCInfo<T> gcObj(t. size); gclist.push_front(gcObj); } addr = t; arraySize = size; if(size > 0) isArray = true; else isArray = false; #ifdef DISPLAY cout « "Constructing GCPtr. "; if(isArray) cout « " Size is " « arraySize « endl; else cout « endl; #endif } // Копирующий конструктор. GCPtr (const GCPtr &ob) { list<GCInfo<T> >::iterator p; p = findPtrlnfo(ob.addr); p->refcount++; // увеличивает счетчик ссыпок на единицу addr = ob.addr; arraySize = ob.arraySize; if(arraySize > 0) isArray = true; else isArray = false; #ifdef DISPLAY cout « "Constructing copy."; if(isArray) cout « " Size is " « arraySize « endl; else cout « endl; #endif } // Деструктор для GCPTr. -GCPtr(); // Собирает мусор. Возвращает true, если хотя бы // один объект был удален, static bool collect(); // Перегружает присваивание указателя GCPtr. Т *operator=(T *t); // Перегружает присваивание одного GCPtr другому GCPtr. GCPtr &operator=(GCPtr &rv); // Возвращает ссылку на объект, на который // указывает этот GCPtr. Т &operator*() { return *addr; } // Возвращает адрес, на который указывает. Т *operator->() { return addr;} // Возвращает ссылку на объект //с индексом, заданным i. Т &operator[](int i) { return addr[i]; } // Функция преобразования для Т *. operator Т *() { return addr; } // Возвращает Iter для начала выделенной памяти. Iter<T> begin() { int size; if(isArray) size = arraySize; else size = 1; return Iter<T>(addr, addr, addr + size); } // Возвращает Iter для элемента, следующего за последним элементом // распределенного в памяти массива. Iter<T> end() { int size; if(isArray) size = arraySize; else size = 1; return Iter<T>(addr + size, addr, addr + size); } // Возвращает размер gclist для этого типа GCPtr. static int gclistSizeO { return gel is t.sizeO ; } // функция-утилита для отображения gclist. static void showlistO; // Очищает gclist, когда программа завершается, static void shutdown(); }; // Выделяет память для статических переменных template <class Т, int size> list<GCInfo<T> > GCPtr<T, size>:rgcliet; template <class T, int size> bool GCPtrcT, size>::first = true; // Деструктор для GCPtr. template <class T, int size> GCPtr<T, size>::-GCPtr() { list<GCInfo<T> >::iterator p; p = findPtrInfo(addr); if(p->refcount) p->refcount—; // уменьшает счетчик // ссылок на единицу #ifdef DISPLAY cout « "GCPtr going out of scope.\n"; #endif // Собирает мусор, когда указатель выходит за пределы области // видимости, collect(); //На практике вы можете захотеть собирать II неиспользуемую память реже, к примеру, когда gclist достигнет // определенного размера или после того как определенное число // указателей GCPtr выйдет за пределы области^видимости, // или когда доступная память иссякнет. } // Сбор мусора. Возвращает true, если хотя бы // один объект был удален, template <class Т, int size> bool GCPtr<T. size>::collect() { bool memfreed = false; #ifdef DISPLAY cout « "Before garbage collection for "; showlist(); #endif list<GCInfo<T> >::iterator p; do { // Просматривает gclist для обнаружения указателей, // ни на что не ссылающихся. for(p = gclist.begin(); р != gclist.end(); р++) { // Если используется, пропустить, if(p->refcount > 0) continue; memfreed = true; // Удаляет неиспользуемый элемент из списка gclist. gclist.remove(*p); // Освобождает память, пока GCPtr не станет равным null, if (p->memPtr) { if(p->isArray) { #ifdef DISPLAY cout « "Deleting array of size " « p->arraySize « endl; #endif delete[] p->memPtr; // удаляет массив } else { #ifdef DISPLAY cout « "Deleting: " "« *(T *) p->memPtr « "\n"; #endif delete p->memPtr; // удаляет единичный элемент } } // Возобновляет поиск, break; } } while(р != gclist.end()); #ifdef DISPLAY cout « "After garbage collection for "; showlist(); #endif return memfreed; } // Перегружает присваивание указателя GCPtr. template <class T, int size> T " GCPtr<T, size>::operator=(T *t) { list<GCInfo<T> >::iterator p; // Во-первых, уменьшает на единицу счетчик ссылок // для области памяти, на которую указывает в данный момент. Р = findPtrlnfo(addr); p->refcount—; // Далее, если новый адрес уже // существует в системе, увеличивает // его счетчик ссыпок. В противном случае создает новый // элемент в списке gclist. Р = findPtrlnfo(t); if(p != gclist.end()) p->refcount++; else { // Создает и запоминает новый элемент. GCInfo<T> gcObj(t, size); gclist.push_front(gcObj); > addr = t; // запоминает адрес, return t; } // Перегружает присваивание одного GCPtr другому GCPtr. template <class T, int size> GCPtr<T, size> & GCPtr<T, size>::operator=(GCPtr &rv) { list<GCInfo<T> >::iterator p; // Сначала уменьшает на единицу счетчик ссылок // для памяти, указываемой в данный момент, р = findPtrInfo(addr); p->refcount—; // Далее увеличивает счетчик ссылок для // нового адреса. р = f indPtr Info (rv. addr) ,- p->refcount++; // увеличивает счетчик ссылок addr = rv.addr;// запоминает адрес, return rv; } // Функция-утилита для отображения списка gclist. template <class T, int size> void GCPtr<T, size>::showlist() { list<GCInfo<T> >::iterator p; cout « "gclist<" « typeid(T) .nameO « " « size « ">:\n"; cout « "memPtr refcount value\n"; if(gclist.begin() == gclist.end()) { cout « " — Empty —\n\n" ; return; } for(p = gclist.begin(); p != gclist.end(); p++) { cout « "[" « (void *)p->memPtr « "]" « " " « p->refcount « " "; if(p->memPtr) cout « " " « *p->memPtr; else cout « " ---"; cout « endl; } cout « endl; } // Находит указатель в списке gclist. template <class T, int size> typename list<GCInfo<T> >::iterator GCPtr<T, size>::findPtrInfo(T *ptr) { list<GCInfo<T> >::iterator p; // Находит ptr в gclist. for(p = gclist.beginO ; p != gclist.end(); p++) if(p->memPtr == ptr) return p; return p; } 11 Очищает gclist, когда программа завершается. template <class T, int size> void GCPtr<T, size>::shutdown() { if (gclistSizeO == 0) return; // список пуст list<GCInfo<T> >::iterator р; for(p = gclist.begin(); p != gclist.end(); p++) { // Устанавливает все счетчики ссылок в ноль. p->refcount = 0; } #ifdef DISPLAY cout « "Before collecting for shutdown() for " « typeid(T).name() « "\n"; #endif collect(); #ifdef DISPLAY cout « "After collecting for shutdown() for " « typeid(T).name() « "\n"; #endif }
|
|
|
|
|