垃圾回收机制:
作为c++程序设计里面的内存分配有三种方法:
作为c++程序设计里面的内存分配有三种方法:
1.即全局变量和静态变量,这些都是存储在静态存储区,生存的周期就是程序运行的周期当程序结束,才释放这些存储空间
2.函数内部的局部变量,这些都是在栈上分配,生存周期是该变量所在的函数的运行周期,函数调用结束,这些存储空间自动释放。
3.动态分配存储空间,在c语言里面我们是通过malloc,free来完成动态存储分配与释放,在c++里是通过new和delete来完成分配和释放存储空间的,生存周期是由new和delete来决定的。
2.函数内部的局部变量,这些都是在栈上分配,生存周期是该变量所在的函数的运行周期,函数调用结束,这些存储空间自动释放。
3.动态分配存储空间,在c语言里面我们是通过malloc,free来完成动态存储分配与释放,在c++里是通过new和delete来完成分配和释放存储空间的,生存周期是由new和delete来决定的。
作为一个垃圾回收器的算法,主要有3种典型的算法:引用计数、标记并清除、以及复制。一般对应的有一个new,必须有一个delete与之对应,不然,就会发生内存泄漏(memory leak)的情况,在实际大规模程序设计中,通过new分配的动态存储空间,往往都忽略了了delete这块存储空间,从而很容易导致内存泄漏。为了实现引用计数的垃圾回收器,必须有某种方法来跟踪指向每块动态分配内存的指针的数量。
问题在于,c++没有内建的机制来确保一个对象知道其他的对象何时指向它。可以建立一个新的支持垃圾回收的指针类型。这就是本章的垃圾回收器采用的算法。为了支持垃圾回收,新的指针类型必须做3件事情:
第一,它必须为使用中的动态分配的对象维护一个引用计数的链表。
第二,它必须跟踪所有的指针运算符,每次某个指针指向一个对象时,都要使这个对象的引用计数增1;每次某个指针重新指向其他的对象的时候,都要使这个对象的引用计数减1。
第三,它必须回收哪些引用计数为0的对象。对于这个新指针类型与普通指针看起来一样,必须支持所有的指针运算,如*和->运算。
问题在于,c++没有内建的机制来确保一个对象知道其他的对象何时指向它。可以建立一个新的支持垃圾回收的指针类型。这就是本章的垃圾回收器采用的算法。为了支持垃圾回收,新的指针类型必须做3件事情:
第一,它必须为使用中的动态分配的对象维护一个引用计数的链表。
第二,它必须跟踪所有的指针运算符,每次某个指针指向一个对象时,都要使这个对象的引用计数增1;每次某个指针重新指向其他的对象的时候,都要使这个对象的引用计数减1。
第三,它必须回收哪些引用计数为0的对象。对于这个新指针类型与普通指针看起来一样,必须支持所有的指针运算,如*和->运算。
在这里我们可以通过标准库的auto_ptr<T>,即智能指针来解决这
个问题,它的工作原理是:通过new来分配存储空间构造一个对象,通过自动调用析构函数来完成对这段内存的释放。由于auto_ptr在超出作用域时,它指向的内存会自动释放,而且 auto_ptr是为ISO c++ 标准称为“严格所有权”的概念设计的,其中auto_ptr拥有它指向的对象。这种所有权可以转换
到其他的auto_ptr,但是在任何情况下,总会有某个auto_ptr拥有这个对象,直到它被销毁。另外,auto_ptr只有在初始化时,才能使用对象的地址对其赋值。
个问题,它的工作原理是:通过new来分配存储空间构造一个对象,通过自动调用析构函数来完成对这段内存的释放。由于auto_ptr在超出作用域时,它指向的内存会自动释放,而且 auto_ptr是为ISO c++ 标准称为“严格所有权”的概念设计的,其中auto_ptr拥有它指向的对象。这种所有权可以转换
到其他的auto_ptr,但是在任何情况下,总会有某个auto_ptr拥有这个对象,直到它被销毁。另外,auto_ptr只有在初始化时,才能使用对象的地址对其赋值。
在源代码中我们创建了四个类
class OutOfRangeExc;
声明一个异常类,用来说明超出某一范围的异常类。这个主要是用来对于指针指的位置超过一定的范围,就通过throw抛出一个异常,由catch来捕获。
声明一个异常类,用来说明超出某一范围的异常类。这个主要是用来对于指针指的位置超过一定的范围,就通过throw抛出一个异常,由catch来捕获。
template < class T > class Iter;
声明一个迭代器类,其作用相当于一个指针,可以完成所有的指针运算,Iter是一个功能上类似STL迭代器的模板类,Iter的主要用处是遍历动态分配的数组元素。它还提供边界检查。它重载 (overload)了大部分的指针运算,*,->,++ptr,--ptr,ptr++,ptr--,ptr[],==,!= ,<,>,>=,<=,-,+。
声明一个迭代器类,其作用相当于一个指针,可以完成所有的指针运算,Iter是一个功能上类似STL迭代器的模板类,Iter的主要用处是遍历动态分配的数组元素。它还提供边界检查。它重载 (overload)了大部分的指针运算,*,->,++ptr,--ptr,ptr++,ptr--,ptr[],==,!= ,<,>,>=,<=,-,+。
构造函数的原型:template <T> Iter( T *p, T *first, T *last );
它跟STL的迭代器不一样,迭代器都是仅仅指向一个位置,这里的Iter指向动态分配的数组元素,数组的大小就是size = last-first,如果size = 0,就是指向一个元素。
它跟STL的迭代器不一样,迭代器都是仅仅指向一个位置,这里的Iter指向动态分配的数组元素,数组的大小就是size = last-first,如果size = 0,就是指向一个元素。
template < class T> struct GCInfo
声明一个已分配内存的所含的信息,也就是说这个类把引用计数和已分配内存封装起来,refcount用来引用计数,memPtr是这块内存的指针,isArray是用来判断分配空间是单个元素还是数组,如果是数组,arraySize就是为数组所分配空间的大小。
声明一个已分配内存的所含的信息,也就是说这个类把引用计数和已分配内存封装起来,refcount用来引用计数,memPtr是这块内存的指针,isArray是用来判断分配空间是单个元素还是数组,如果是数组,arraySize就是为数组所分配空间的大小。
构造函数的原型:
GCInfo(T *mPtr, unsigned size = 0 );
当构造一个这样的对象的时候,引用计数设为1,同时,这块内存的指针指向所分配的对象,初始化设定是否是数组以及数组的大小。
GCInfo(T *mPtr, unsigned size = 0 );
当构造一个这样的对象的时候,引用计数设为1,同时,这块内存的指针指向所分配的对象,初始化设定是否是数组以及数组的大小。
template < class T, int size = 0 > class GCPtr
GCPtr维护了一个链表,这个链表与GCPtr分配的每一块内存的引用计数有关。每次GCPtr指向一块内存时,调用构造函数或者复制构造函数来构造一个指向这块内存的一个对象,并放入链表中,然后这块内存的引用计数增1。当GCPtr超过作用域,就会自动调用析构函数,此时它所指向的内存的引用计数就会减1。当引用计数为0的时候,这块内存就被释放。
GCPtr维护了一个链表,这个链表与GCPtr分配的每一块内存的引用计数有关。每次GCPtr指向一块内存时,调用构造函数或者复制构造函数来构造一个指向这块内存的一个对象,并放入链表中,然后这块内存的引用计数增1。当GCPtr超过作用域,就会自动调用析构函数,此时它所指向的内存的引用计数就会减1。当引用计数为0的时候,这块内存就被释放。
函数构造的原型:
template < class T, int size >GCPtr<T,size>::GCPtr(T *t );
template < class T, int size >GCPtr<T, size>::GCPtr(const GCPtr &ob);
这是将一个普通指针转化成GCPtr类型,
然后建立一个静态的链表:static list<GCInfo<T> > gclist;
这个链表里面存放的就是每一块内存,对于constructor或者copy constructor在创建对象的时候,首先需要遍历该链表,看里面是否有相同的对象,如果有,则指向该内存的指针数增加1,即引用计数增1。否则,建立一个GCInfo对象,这个对象所指的就是所分配的内存,然后把这块内存放到链表中,对于所分配的内存需要判断是否是为数组分配的内存。对于copy constructor 在创建对象的时候,仍然去遍历这个链表,将其内存所对应的引用计数增1。如果没有找到,仍然增1,同时把所复制的对象赋*this,这样就又建立了一个指向该内存对象。
这个链表里面存放的就是每一块内存,对于constructor或者copy constructor在创建对象的时候,首先需要遍历该链表,看里面是否有相同的对象,如果有,则指向该内存的指针数增加1,即引用计数增1。否则,建立一个GCInfo对象,这个对象所指的就是所分配的内存,然后把这块内存放到链表中,对于所分配的内存需要判断是否是为数组分配的内存。对于copy constructor 在创建对象的时候,仍然去遍历这个链表,将其内存所对应的引用计数增1。如果没有找到,仍然增1,同时把所复制的对象赋*this,这样就又建立了一个指向该内存对象。
然后就是assignment constructor:
//GCPtr &operator = ( T * );
T *operator = ( T * );
GCPtr &operator = ( GCPtr & );
将一个指针赋给另外一个指针的时候:
template < class T, int size >T* GCPtr < T, size > ::operator = ( T * t )
此时依然要遍历这个链表,找到当前的指针所指的内存,并把这个内存相关的引用计数减1,然后在在链表中寻找与我们需要的对象所存放的内存,如果找到,那就是说已经有指针指向这个对象了,此时需要把这个指针所指向的内存增1,如果没有,就需要建立一个GCInfo对象并为其分配内存空间,并将这块内存放到链表中。
//GCPtr &operator = ( T * );
T *operator = ( T * );
GCPtr &operator = ( GCPtr & );
将一个指针赋给另外一个指针的时候:
template < class T, int size >T* GCPtr < T, size > ::operator = ( T * t )
此时依然要遍历这个链表,找到当前的指针所指的内存,并把这个内存相关的引用计数减1,然后在在链表中寻找与我们需要的对象所存放的内存,如果找到,那就是说已经有指针指向这个对象了,此时需要把这个指针所指向的内存增1,如果没有,就需要建立一个GCInfo对象并为其分配内存空间,并将这块内存放到链表中。
template < class T, int size >
GCPtr <T, size >& GCPtr <T, size >::operator = ( GCPtr< T, size >& gc );
对于GCPtr对象的复制,我们可以模仿copy constructor来写。不同的是,对于assignment constructor需要删除当前所指的对象,然后把另外一个对象赋给当前的这个指针。
GCPtr <T, size >& GCPtr <T, size >::operator = ( GCPtr< T, size >& gc );
对于GCPtr对象的复制,我们可以模仿copy constructor来写。不同的是,对于assignment constructor需要删除当前所指的对象,然后把另外一个对象赋给当前的这个指针。
对于析构函数的调用
函数原型
template <class T, int size >GCPtr < T, size >::~GCPtr ( );
收依然是遍历该内存链表,每调用一次析构函数,所析构的对象就是当前指针所指向的那块内存,如果此时内存的引用计数不为0,此时这块内存所对应的引用计数减 1。然后调用一个辅助函数collect()。这是一个静态函数,这个辅助函数的目的就是清除那些引用计数为0的内存,将这些内存自动清除,如果对应是单个对象的内存,清除时就调用delete p,如果是数组,调用delete [] p,如果需要的化,可以显示出链
表中的内存信息。 showlist()也是一个辅助函数,它是用来显示整个链表里面的内存信息。除此之外,GCPtr还重载了 *,->,[]运算符,还定义一个operator T *()的转换函数,这是把GCPtr转化成T*的指针对于其他的一些指针运算符,事实上,因为Iter类已经提供了这些操作。
函数原型
template <class T, int size >GCPtr < T, size >::~GCPtr ( );
收依然是遍历该内存链表,每调用一次析构函数,所析构的对象就是当前指针所指向的那块内存,如果此时内存的引用计数不为0,此时这块内存所对应的引用计数减 1。然后调用一个辅助函数collect()。这是一个静态函数,这个辅助函数的目的就是清除那些引用计数为0的内存,将这些内存自动清除,如果对应是单个对象的内存,清除时就调用delete p,如果是数组,调用delete [] p,如果需要的化,可以显示出链
表中的内存信息。 showlist()也是一个辅助函数,它是用来显示整个链表里面的内存信息。除此之外,GCPtr还重载了 *,->,[]运算符,还定义一个operator T *()的转换函数,这是把GCPtr转化成T*的指针对于其他的一些指针运算符,事实上,因为Iter类已经提供了这些操作。
垃圾回收机制的头文件代码:
// A single-threaded garbage collector.
#ifndef _H_GARBAGE_COLLECTOR
#define _H_GARBAGE_COLLECTOR
#ifndef _H_GARBAGE_COLLECTOR
#define _H_GARBAGE_COLLECTOR
#i nclude < iostream >
#i nclude < list >
#i nclude < typeinfo >
#i nclude < cstdlib >
#i nclude < list >
#i nclude < typeinfo >
#i nclude < cstdlib >
using namespace std;
#define DISPLAY
// Exception thrown when an attempt is made to
// use an Iter that exceeds the range of the underlying object.
class OutOfRangeExc {
// Add functionality if needed by your application.
};
// use an Iter that exceeds the range of the underlying object.
class OutOfRangeExc {
// Add functionality if needed by your application.
};
// An iterator-like class for cycling through arrays
// that are pointed to by GCPtrs. Iter pointers
// ** do not ** participate in or affect garbage
// collection. Thus, an Iter pointing to
// some object does not prevent that object
// from being recycled.
template < class T > class Iter
{
public:
Iter ( ):_ptr ( 0 ), _end ( 0 ), _begin ( 0 ), _length ( 0 ) { }
Iter ( T *p, T *first, T *last ) : _ptr ( p ), _end ( last ), _begin ( first )
{ _length = last - first ; }
// that are pointed to by GCPtrs. Iter pointers
// ** do not ** participate in or affect garbage
// collection. Thus, an Iter pointing to
// some object does not prevent that object
// from being recycled.
template < class T > class Iter
{
public:
Iter ( ):_ptr ( 0 ), _end ( 0 ), _begin ( 0 ), _length ( 0 ) { }
Iter ( T *p, T *first, T *last ) : _ptr ( p ), _end ( last ), _begin ( first )
{ _length = last - first ; }
//return length of sequence to which this Iter points
unsigned size ( ) const { return _length; }
T & operator * ( );
T * operator -> ( );
unsigned size ( ) const { return _length; }
T & operator * ( );
T * operator -> ( );
//prefix
Iter& operator ++ ( );
Iter &operator -- ( );
Iter& operator ++ ( );
Iter &operator -- ( );
//Postfix
Iter operator ++ ( int );
Iter operator -- ( int );
Iter operator ++ ( int );
Iter operator -- ( int );
T & operator [ ] ( int );
bool operator == (const Iter& );
bool operator != (const Iter& );
bool operator < ( const Iter& );
bool operator > ( const Iter & );
bool operator >= ( const Iter & );
bool operator <= (const Iter & );
bool operator != (const Iter& );
bool operator < ( const Iter& );
bool operator > ( const Iter & );
bool operator >= ( const Iter & );
bool operator <= (const Iter & );
Iter& operator - ( int );
Iter& operator + ( int );
Iter& operator + ( int );
//return number of elements between two Iters
int operator - ( const Iter < T > & );
private:
T *_ptr; // current pointer value
T *_end; //points to element one past end
T *_begin; //points to start of allocated array
unsigned _length;// length of sequence
int operator - ( const Iter < T > & );
private:
T *_ptr; // current pointer value
T *_end; //points to element one past end
T *_begin; //points to start of allocated array
unsigned _length;// length of sequence
};
///////////////////////////////////////
// This class defines an element that is stored
// in the garbage collection information list.
//
template < class T> struct GCInfo
{
unsigned refcount; // current reference count
T *memPtr; // pointer to allocated memory
/* isArray is true if memPtr points
to an allocated array. It is false
otherwise. */
bool isArray; // true if pointing to array
/* If memPtr is pointing to an allocated
array, then arraySize contains its size */
unsigned arraySize; // size of array
///////////////////////////////////////
// This class defines an element that is stored
// in the garbage collection information list.
//
template < class T> struct GCInfo
{
unsigned refcount; // current reference count
T *memPtr; // pointer to allocated memory
/* isArray is true if memPtr points
to an allocated array. It is false
otherwise. */
bool isArray; // true if pointing to array
/* If memPtr is pointing to an allocated
array, then arraySize contains its size */
unsigned arraySize; // size of array
// Here, mPtr points to the allocated memory.
// If this is an array, then size specifies
// the size of the array.
GCInfo(T *mPtr, unsigned size=0) {
refcount = 1;
memPtr = mPtr;
if(size != 0)
isArray = true;
else
isArray = false;
arraySize = size;
}
};
// Overloading operator== allows GCInfos to be compared.
// This is needed by the STL list class.
// If this is an array, then size specifies
// the size of the array.
GCInfo(T *mPtr, unsigned size=0) {
refcount = 1;
memPtr = mPtr;
if(size != 0)
isArray = true;
else
isArray = false;
arraySize = size;
}
};
// Overloading operator== allows GCInfos to be compared.
// This is needed by the STL list class.
template < class T>
bool operator == ( const GCInfo < T> & ob1, const GCInfo < T> & ob2 )
{
return ob1.memPtr == ob2.memPtr;
}
////////////////////////////////////////////////////////////
/*
GCPtr implements a pointer type that uses
garbage collection to release unused memory.
A GCPtr must only be used to point to memory
that was dynamically allocated using new.
When used to refer to an allocated array,
specify the array size. */
bool operator == ( const GCInfo < T> & ob1, const GCInfo < T> & ob2 )
{
return ob1.memPtr == ob2.memPtr;
}
////////////////////////////////////////////////////////////
/*
GCPtr implements a pointer type that uses
garbage collection to release unused memory.
A GCPtr must only be used to point to memory
that was dynamically allocated using new.
When used to refer to an allocated array,
specify the array size. */
template < class T, int size = 0 > class GCPtr
{
public:
typedef Iter<T> GCiterator; // Define an iterator type for GCPtr<T>.
GCPtr(T *t= 0 ) ;
GCPtr(const GCPtr &);
//GCPtr &operator = ( T * );
T *operator = ( T * ); // overload assignment of pointer to GCPtr;
GCPtr &operator = ( GCPtr & ); //overload assignment of GCPtr to GCPtr
{
public:
typedef Iter<T> GCiterator; // Define an iterator type for GCPtr<T>.
GCPtr(T *t= 0 ) ;
GCPtr(const GCPtr &);
//GCPtr &operator = ( T * );
T *operator = ( T * ); // overload assignment of pointer to GCPtr;
GCPtr &operator = ( GCPtr & ); //overload assignment of GCPtr to GCPtr
~GCPtr ( );
static bool collect ( ); // Collect garbage. returns true if at least one object was freed
T &operator * ( ) { return *addr; } // return a reference to the object pointed
T * operator -> () {return addr;} // return the address being pointed to
T &operator [ ] ( int index )
{ return addr [ index ] ; }
// return a reference to the object at the index specified by i
T &operator * ( ) { return *addr; } // return a reference to the object pointed
T * operator -> () {return addr;} // return the address being pointed to
T &operator [ ] ( int index )
{ return addr [ index ] ; }
// return a reference to the object at the index specified by i
operator T* ( ) { return addr; } //conversion function to T *
Iter<T> begin ( ) ; // return an Iter to the start of the allocated memory
Iter<T> end ( ); // return an Iter to one past the end of an allocated array
Iter<T> begin ( ) ; // return an Iter to the start of the allocated memory
Iter<T> end ( ); // return an Iter to one past the end of an allocated array
static int gclistSize ( )
{ return gclist.size ( ); } //return the size of gclist for this type
static void showlist ( ); // a utility function that display gclist;
static void shutdown ( ); // Clear gclist when program exits
{ return gclist.size ( ); } //return the size of gclist for this type
static void showlist ( ); // a utility function that display gclist;
static void shutdown ( ); // Clear gclist when program exits
private:
static list< GCInfo< T > > gclist ;
// gclist maintains the garbage collection list.
// addr points to the allocated memory to which this GCPtr pointer currently points.
T *addr;
//isArray is true if this GCPtr points to an allocated array. It is false otherwise.
bool isArray; // true if pointing to array
// If this GCPtr is pointing to an allocated array, then arraySize contains its size.
unsigned arraySize; // size of the array
static list< GCInfo< T > > gclist ;
// gclist maintains the garbage collection list.
// addr points to the allocated memory to which this GCPtr pointer currently points.
T *addr;
//isArray is true if this GCPtr points to an allocated array. It is false otherwise.
bool isArray; // true if pointing to array
// If this GCPtr is pointing to an allocated array, then arraySize contains its size.
unsigned arraySize; // size of the array
static bool first; // true when first GCPtr is created
// Return an interator to pointer info in gclist.
typename list<GCInfo<T> >::iterator findPtrInfo(T *ptr);
};
/////////////////////////////////////////////////
// Return an interator to pointer info in gclist.
typename list<GCInfo<T> >::iterator findPtrInfo(T *ptr);
};
/////////////////////////////////////////////////
#endif
转载于:https://blog.51cto.com/familyandjob/110494