Java内存垃圾收集机制

基本概念

堆中为对象分配的存储不再被使用时称为垃圾。当堆中的内存块不再被程序访问时会产生垃圾。
当程序中没有指针指向被分配的内存块时会发生内存泄露。
当堆满的时候有时会回收这些不用的空间,面向堆的底部压缩空间,并标记为可用,这样的操作成为垃圾收集。垃圾收集的目的在于清除不再使用的对象。
当一个内存块被解除了分配的指针,引用这个被删除的块的指针成为了悬挂指针。

GC基本原理

Java的内存管理实际上就是对象的管理,其中包括对象的分配和释放。
对于程序员来说,分配对象使用new关键字;释放对象时,只要将对象所有引用赋值为null,让程序不能够再访问到这个对象,我们称该对象为/"不可达的/".GC将负责回收所有/"不可达/"对象的内存空间。
GC通过确定对象是否被活动对象引用来确定是否收集该对象。GC首先要判断该对象是否是时候可以收集。两种常用的方法是引用计数和对象引用遍历。

引用计数收集器

原理:引用计数是垃圾收集器中的早期策略。在这种方法中,堆中每个对象(不是引用)都有一个引用计数。当一个对象被创建时,且将该对象分配给一个变量,该变量计数设置为1。当任何其它变量被赋值为这个对象的引用时,计数加1(a = b,则b引用的对象+1),但当一个对象的某个引用超过了生命周期或者被设置为一个新值时,对象的引用计数减1。任何引用计数为0的对象可以被当作垃圾收集。当一个对象被垃圾收集时,它引用的任何对象计数减1。
引用计数跟踪一个块被多少指针引用。
需要为每个块计数,因此可以在free_list节点结构中增加一个计数。
当新调用一个块时,计数设为1。
当有指针被分配时,需要修改计数。
当一个块的计数回到0时,返回free_list。

优点:

引用计数收集器可以很快的执行,交织在程序运行中。对程序不被长时间打断的实时环境比较有利。

缺点:

无法检测出循环引用。如父对象有一个对子对象的引用,子对象反过来引用父对象。这样,他们的引用计数永远不可能为0。

标记-清除收集器

原理:这种收集器首先遍历对象图并标记可到达的对象,然后扫描堆栈以寻找未标记对象并释放它们的内存。这种收集器一般使用单线程工作并停止其他操作。并且,由于它只是清除了那些未标记的对象,而并没有对标记对象进行压缩,导致会产生大量内存碎片,从而浪费内存。

过程:
首先所有内存块的标志位(mark bit)初始化为0.
当分配一个新节点(左边)的时候,右边的过程被执行。

         q=new node();       if(free_list==null)
			 mark_sweep();
		            if(free_list!=null)
			 q=free_list;
	                         free_list=free_list.next;
		             }
		            else abort(‘heap full’)

最后的abort语句表示当垃圾收集器失败的回收任何内存块,迫使程序异常终止

mark_sweep()的过程分为两步:
mark过程:遍历运行时栈中的指针链表可以访问的堆,把堆的标识记为1。

Mark(R):         if(R.MB==0)
			R.MB=1;
		         if(R. next!=null)
			Mark(R.next);


sweep过程:遍历整个堆,把所有没有标记的堆返回给free_list,并且不标记所有在第一部分中标记的堆。h和n表示heap的底部和顶部。

Sweep():         i=h;
		while(i<=n){
		   if(i.MB==0)
		      free(i);
	                else i.MB=0;
		  i=i+1;
		}

Free(N)把N引用的节点恢复到free_list

 free(N):     N.next=free_list;
		     free_list=N;


优点:

也许永远不需要运行跟踪收集器,因为只有在heap满的时候才运行。
跟踪收集器可以发现并释放所有不可用的内存

缺点:

GC需要停止其他的活动。这种方法意味着所有与应用程序相关的工作停止,只有GC运行。在运行期间这种不可预期的中断也许是某些应用不能接受的。

复制收集器(拷贝回收)

//自己动手实践过的一种回收器

原理:这种收集器将堆栈分为两个域,常称为半空间。每次仅使用一半的空间,JVM生成的新对象则放在另一半空间中。GC运行时,它把可到达对象复制到另一半空间,从而压缩了堆栈。这种方法适用于短生存期的对象,持续复制长生存期的对象则导致效率降低。并且对于指定大小堆来说,需要两倍大小的内存,因为任何时候都只使用其中的一半。

优点:

相比于标记-清除收集器,复制收集器较快。

缺点:

只能使用一半的堆空间。

其他常见收集器

标记-压缩收集器
有时也叫标记-清除-压缩收集器,与标记-清除收集器有相同的标记阶段。在第二阶段,则把标记对象复制到堆栈的新域中以便压缩堆栈。这种收集器也停止其他操作。

增量收集器
增量收集器把堆栈分为多个域,每次仅从一个域收集垃圾,也可理解为把堆栈分成一小块一小块,每次仅对某一个块进行垃圾收集。这会造成较小的应用程序中断时间,使得用户一般不能觉察到垃圾收集器正在工作。

分代收集器(世代回收)
复制收集器的缺点是:每次收集时,所有的标记对象都要被拷贝,从而导致一些生命周期很长的对象被来回拷贝多次,消耗大量的时间。而分代收集器则可解决这个问题,分代收集器把堆栈分为两个或多个域,用以存放不同寿命的对象。JVM生成的新对象一般放在其中的某个域中。过一段时间,继续存在的对象(非短命对象)将获得使用期并转入更长寿命的域中。分代收集器对不同的域使用不同的算法以优化性能。

并行收集器
并行收集器使用某种传统的算法并使用多线程并行的执行它们的工作。在多CPU机器上使用多线程技术可以显着的提高java应用程序的可扩展性。

实例分析

class test
{
      Public static void main(String a[])
      {
           Object o1=new Object();
           Object o2=new Object();
           o2=o1;
           //此行为第6行
      }
}


finalize函数


finalize是位于Object类的一个方法,该方法的访问修饰符为protected,由于所有类为Object的子类,因此用户类很容易访问到这个方法。由于,finalize函数没有自动实现链式调用,我们必须手动的实现,因此finalize函数的最后一个语句通常是super.finalize()。通过这种方式,我们可以实现从下到上实现finalize的调用,即先释放自己的资源,然后再释放父类的资源。

通常,finalize用于一些不容易控制、并且非常重要资源的释放,例如一些I/O的操作,数据的连接。这些资源的释放对整个应用程序是非常关键的。在这种情况下,程序员应该以通过程序本身管理(包括释放)这些资源为主,以finalize函数释放资源方式为辅,形成一种双保险的管理机制,而不应该仅仅依靠finalize来释放资源。

class MyObject{
	Test main; //记录Test对象,在finalize中时用于恢复可达性
	public MyObject(Test t)
	{
	main=t; //保存Test 对象
	}
   protected void finalize()
   {
   main.ref=this;// 恢复本对象,让本对象可达
   System.out.println(/"This is finalize/");//用于测试finalize只运行一次
   }
}
   class Test {
   MyObject ref;
   public static void main(String[] args) {
   Test test=new Test();
   test.ref=new MyObject(test);
   test.ref=null; //MyObject对象为不可达对象,finalize将被调用
   System.gc();
   if (test.ref!=null) System.out.println(/"My Object还活着/");
   }
}

运行结果

 This is finalize  MyObject还活着
此例子中,需要注意的是虽然MyObject对象在finalize中变成可达对象,但是下次回收时候,finalize却不再被调用,因为finalize函数最多只调用一次。


使用垃圾收集器要注意的地方

下面将提出一些有关垃圾收集器要注意的地方,垃圾收集器知识很多,下面只列出一部分必要的知识:
每个对象只能调用finalize()方法一次。如果在finalize()方法执行时产生异常(exception),则该对象仍可以被垃圾收集器收集。
垃圾收集器跟踪每一个对象,收集那些不可触及的对象(即该对象不再被程序引用 了),回收其占有的内存空间。但在进行垃圾收集的时候,垃圾收集器会调用该对象的finalize()方法(如果有)。如果在finalize()方法中,又使得该对象被程序引用(俗称复活了),则该对象就变成了可触及的对象,暂时不会被垃圾收集了。但是由于每个对象只能调用一次finalize()方法,所以每个对象也只可能 "复活 "一次。

Java语言允许程序员为任何方法添加finalize()方法,该方法会在垃圾收集器交换回收对象之前被调用。但不要过分依赖该方法对系统资源进行回收和再利用,因为该方法调用后的执行结果是不可预知的。
垃圾收集器不可以被强制执行,但程序员可以通过调研System.gc方法来建议执行垃圾收集。记住,只是建议。一般不建议自己写System.gc,因为会加大垃圾收集工作量。

对于GC来说,当程序员创建对象时,GC就开始监控这个对象的地址、大小以及使用情况。通常,GC采用有向图的方式记录和管理堆(heap)中的所有对象。通过这种方式确定哪些对象是/"可达的/",哪些对象是/"不可达的/".当GC确定一些对象为/"不可达/"时,GC就有责任回收这些内存空间。但是,为了保证GC能够在不同平台实现的问题,Java规范对GC的很多行为都没有进行严格的规定。例如,对于采用什么类型的回收算法、什么时候进行回收等重要问题都没有明确的规定。因此,不同的JVM的实现者往往有不同的实现算法。这也给Java程序员的开发带来行多不确定性。本文研究了几个与GC工作相关的问题,努力减少这种不确定性给Java程序带来的负面影响。


增量式GC( Incremental GC )

GC在JVM中通常是由一个或一组进程来实现的,它本身也和用户程序一样占用heap空间,运行时也占用CPU.当GC进程运行时,应用程序停止运行。因此,当GC运行时间较长时,用户能够感到Java程序的停顿,另外一方面,如果GC运行时间太短,则可能对象回收率太低,这意味着还有很多应该回收的对象没有被回收,仍然占用大量内存。因此,在设计GC的时候,就必须在停顿时间和回收率之间进行权衡。一个好的GC实现允许用户定义自己所需要的设置,例如有些内存有限有设备,对内存的使用量非常敏感,希望GC能够准确的回收内存,它并不在意程序速度的放慢。另外一些实时网络游戏,就不能够允许程序有长时间的中断。增量式GC就是通过一定的回收算法,把一个长时间的中断,划分为很多个小的中断,通过这种方式减少GC对用户程序的影响。虽然,增量式GC在整体性能上可能不如普通GC的效率高,但是它能够减少程序的最长停顿时间。
Sun JDK提供的HotSpot JVM就能支持增量式GC.HotSpot JVM缺省GC方式为不使用增量GC,为了启动增量GC,我们必须在运行Java程序时增加-Xincgc的参数。HotSpot JVM增量式GC的实现是采用Train GC算法。它的基本想法就是,将堆中的所有对象按照创建和使用情况进行分组(分层),将使用频繁高和具有相关性的对象放在一队中,随着程序的运行,不断对组进行调整。当GC运行时,它总是先回收最老的(最近很少访问的)的对象,如果整组都为可回收对象,GC将整组回收。这样,每次GC运行只回收一定比例的不可达对象,保证程序的顺畅运行。

程序如何与GC进行交互

Java2增强了内存管理功能, 增加了一个java.lang.ref包,其中定义了三种引用类。这三种引用类分别为SoftReference、WeakReference和PhantomReference.通过使用这些引用类,程序员可以在一定程度与GC进行交互,以便改善GC的工作效率。这些引用类的引用强度介于可达对象和不可达对象之间。
创建一个引用对象也非常容易,例如如果你需要创建一个Soft Reference对象,那么首先创建一个对象,并采用普通引用方式(可达对象);然后再创建一个SoftReference引用该对象;最后将普通引用设置为null.通过这种方式,这个对象就只有一个Soft Reference引用。同时,我们称这个对象为Soft Reference 对象

Soft Reference的主要特点是据有较强的引用功能。只有当内存不够的时候,才进行回收这类内存,因此在内存足够的时候,它们通常不被回收。另外,这些引用对象还能保证在Java抛出OutOfMemory 异常之前,被设置为null.它可以用于实现一些常用图片的缓存,实现Cache的功能,保证最大限度的使用内存而不引起OutOfMemory.以下给出这种引用类型的使用伪代码;

//申请一个图像对象
Image image=new Image();//创建Image对象
…
//使用 image
…
//使用完了image,将它设置为soft 引用类型,并且释放强引用;SoftReference sr=new SoftReference(image);image=null;
…
//下次使用时
if (sr!=null) image=sr.get();
else{
//由于GC由于低内存,已释放image,因此需要重新装载;
image=new Image();
sr=new SoftReference(image);
}

Weak引用对象与Soft引用对象的最大不同就在于:GC在进行回收时,需要通过算法检查是否回收Soft引用对象,而对于Weak引用对象,GC总是进行回收。Weak引用对象更容易、更快被GC回收。


最后贴上自己写的拷贝回收器GC代码(需配合别的代码使用,因为函数栈是需要另外维护的)

世代回收写的不好,就不贴出来了,当然这个拷贝回收也写的很烂,而且我也不知道对不对,但是实验的十几个测试用例都能跑通
//一下是测试用例的,拷贝回收部分结果显示 
 result-of-ThousandsObject ==================================================
  Beforce Heap_From=244byte Heap_To=0byte
   Time : 0 ms
  Last Heap_From=0byte Heap_To=76byte
  TO Busy = 29.688%
  From->->->->->->GC...->->->->->->To
  Beforce Heap_From=0byte Heap_To=244byte
   Time : 0 ms
  Last Heap_From=56byte Heap_TO=0byte
  From Busy = 21.875%
  To->->->->->->->GC...->->->->->From
  Beforce Heap_From=252byte Heap_To=0byte
   Time : 0 ms
  Last Heap_From=0byte Heap_To=28byte
  TO Busy = 10.938%
  From->->->->->->GC...->->->->->->To
  Beforce Heap_From=0byte Heap_To=252byte
   Time : 0 ms
  Last Heap_From=56byte Heap_TO=0byte
  From Busy = 21.875%
  To->->->->->->->GC...->->->->->From
  Beforce Heap_From=252byte Heap_To=0byte
   Time : 0 ms
  Last Heap_From=0byte Heap_To=28byte
  TO Busy = 10.938%
  From->->->->->->GC...->->->->->->To
  Beforce Heap_From=0byte Heap_To=252byte
   Time : 0 ms
  Last Heap_From=56byte Heap_TO=0byte
  From Busy = 21.875%
  To->->->->->->->GC...->->->->->From
  Beforce Heap_From=252byte Heap_To=0byte
   Time : 0 ms
  Last Heap_From=0byte Heap_To=28byte
  TO Busy = 10.938%
  From->->->->->->GC...->->->->->->To
  Beforce Heap_From=0byte Heap_To=252byte
   Time : 0 ms
  Last Heap_From=56byte Heap_TO=0byte
  From Busy = 21.875%
  To->->->->->->->GC...->->->->->From
  Beforce Heap_From=252byte Heap_To=0byte
   Time : 0 ms
  Last Heap_From=0byte Heap_To=28byte
  TO Busy = 10.938%
  From->->->->->->GC...->->->->->->To
  Beforce Heap_From=0byte Heap_To=252byte
   Time : 0 ms
  Last Heap_From=56byte Heap_TO=0byte
  From Busy = 21.875%
  To->->->->->->->GC...->->->->->From
  Beforce Heap_From=252byte Heap_To=0byte
   Time : 0 ms
  Last Heap_From=0byte Heap_To=28byte
  TO Busy = 10.938%
  From->->->->->->GC...->->->->->->To
//以上是测试用例的,拷贝回收结果显示
#define HEAPSIZE 512
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <windows.h>


// The Gimple Garbage Collector.

//===============================================================//
// The Java Heap data structure.

/*   
 ----------------------------------------------------
 |                        |                         |
 ----------------------------------------------------
 ^\                      /^
 | \<~~~~~~~ size ~~~~~>/ |
 from                       to
 */
// structures


struct JavaHeap {
	int size;         // in bytes, note that this if for semi-heap size
	char *from;       // the "from" space pointer
	char *fromFree;   // the next "free" space in the from space
	char *to;         // the "to" space pointer
	char *toStart;    // "start" address in the "to" space
	char *toNext;     // "next" free space pointer in the to space
};

// The Java heap, which is initialized by the following
// "heap_init" function.
struct JavaHeap heap;
static void Tiger_gc();

void printCurrentHeap();

void move(int *p);
void removeLocalObject(int *p);
void removeFromalObject(int* p);
int TestTime(LARGE_INTEGER linkTableStart, LARGE_INTEGER linkTableNow, LARGE_INTEGER m_liPerfFreq);
int ssss = 0;
	char *temp;
	float bt;

// Lab 4, exercise 10:
// Given the heap size (in bytes), allocate a Java heap
// in the C heap, initialize the relevant fields.
void Tiger_heap_init(int heapSize) {
	// You should write 7 statement here:
	// #1: allocate a chunk of memory of size "heapSize" using "malloc"
	char *p = malloc(heapSize);
	// #2: initialize the "size" field, note that "size" field
	// is for semi-heap, but "heapSize" is for the whole heap.
	heap.size = heapSize / 2;
	// #3: initialize the "from" field (with what value?)
	heap.from = p;
	// #4: initialize the "fromFree" field (with what value?)
	heap.fromFree = p;
	// #5: initialize the "to" field (with what value?)
	heap.to = p + heap.size;
	// #6: initizlize the "toStart" field with NULL;
	heap.toStart = NULL;
	// #7: initialize the "toNext" field with NULL;
	heap.toNext = heap.to;
	return;
}

// The "prev" pointer, pointing to the top frame on the GC stack.
// (see part A of Lab 4)
void *prev = 0;
//===============================================================//
// Object Model And allocation

// Lab 4: exercise 11:
// "new" a new object, do necessary initializations, and
// return the pointer (reference).
/*    ----------------
 | vptr      ---|----> (points to the virtual method table)
 |--------------|
 | isObjOrArray | (0: for normal objects)
 |--------------|
 | length       | (this field should be empty for normal objects)
 |--------------|
 | forwarding   |
 |--------------|\
p---->| v_0          | \
 |--------------|  s
 | ...          |  i
 |--------------|  z
 | v_{size-1}   | /e
 ----------------/
 */
// Try to allocate an object in the "from" space of the Java
// heap. Read Tiger book chapter 13.3 for details on the
// allocation.0p
// There are two cases to consider:
//   1. If the "from" space has enough space to hold this object, then
//      allocation succeeds, return the apropriate address (look at
//      the above figure, be careful);
//   2. if there is no enough space left in the "from" space, then
//      you should call the function "Tiger_gc()" to collect garbages.
//      and after the collection, there are still two sub-cases:
//        a: if there is enough space, you can do allocations just as case 1;
//        b: if there is still no enough space, you can just issue
//           an error message ("OutOfMemory") and exit.
//           (However, a production compiler will try to expand
//           the Java heap.)
void *Tiger_new(void *vtable, int size) {
	// Your code here:

	char *p;
	int i;
	if (heap.toStart == NULL) {

		p = heap.fromFree;
		if (size > heap.to - heap.fromFree) {
		printf("\t\tBeforce Heap_From=%dbyte Heap_To=%dbyte\n",(heap.fromFree-heap.from),(heap.toNext - heap.to));
			(heap.toStart == heap.to)?(bt = ((float)(heap.fromFree-heap.from) / (float)heap.size) *100):
			(bt = ((float)(heap.toNext-heap.to) / (float)heap.size) *100);
	
			heap.toNext = heap.toStart = heap.to;
			Tiger_gc();		
			p = heap.toNext;
			printf("\n\t\tLast Heap_From=%dbyte Heap_To=%dbyte\n",(heap.fromFree-heap.from),(heap.toNext - heap.to));
			bt = ((float)(heap.toNext-heap.to) / (float)heap.size) *100;
			printf("\t\tTO Busy = %0.3f%%\n\t\tFrom->->->->->->GC...->->->->->->To\n",bt);
		}
		if (size > heap.to + heap.size - heap.toNext) {
			printf("right OBJECT OutOfMemory!\n");
			exit(1);
		}
	} else if (heap.toStart == heap.to) {

		p = heap.toNext;
		if (size > heap.to + heap.size - heap.toNext) {
		printf("\t\tBeforce Heap_From=%dbyte Heap_To=%dbyte\n",(heap.fromFree-heap.from),(heap.toNext - heap.to));
		
			
			heap.toStart = NULL;
			heap.fromFree = heap.from;
			Tiger_gc();
		
			
			p = heap.fromFree;
				printf("\n\t\tLast Heap_From=%dbyte Heap_TO=%dbyte\n",(heap.fromFree-heap.from),(heap.toNext - heap.to));
			(bt = ((float)(heap.fromFree-heap.from) / (float)heap.size) *100);
			printf("\t\tFrom Busy = %0.3f%%\n\t\tTo->->->->->->->GC...->->->->->From\n",bt);
		}
		if (size > heap.to - heap.fromFree) {
			printf("left OBJECT OutOfMemory!\n");
			exit(1);
		}
	}
	//memset(p, 0, size);
	((int*) p)[0] = (int) vtable;
	((int*) p)[1] = 0;
	((int*) p)[2] = 0;
	((int*) p)[3] = NULL;

	for(i = 0; i < (size / 4 - 4); i++)
	{
		((int*) p)[4 + i] = NULL;
	}
	(heap.toStart == NULL) ? (heap.fromFree += size) : (heap.toNext += size);
	return p;

}

// "new" an array of size "length", do necessary
// initializations. And each array cosmes with an
// extra "header" storing the array length and other inFromation.
/*    ----------------
 | vptr         | (this field should be empty for an array)
 |--------------|
 | isObjOrArray | (1: for array)
 |--------------|
 | length       |
 |--------------|
 | forwarding   |
 |--------------|\
p---->| e_0          | \
 |--------------|  s
 | ...          |  i
 |--------------|  z
 | e_{length-1} | /e
 ----------------/
 */
// Try to allocate an array object in the "from" space of the Java
// heap. Read Tiger book chapter 13.3 for details on the
// allocation.
// There are two cases to consider:
//   1. If the "from" space has enough space to hold this array object, then
//      allocation succeeds, return the apropriate address (look at
//      the above figure, be careful);
//   2. if there is no enough space left in the "from" space, then
//      you should call the function "Tiger_gc()" to collect garbages.
//      and after the collection, there are still two sub-cases:
//        a: if there is enough space, you can do allocations just as case 1;
//        b: if there is still no enough space, you can just issue
//           an error message ("OutOfMemory") and exit.
//           (However, a production compiler will try to expand
//           the Java heap.)
void *Tiger_new_array(int length) {

	char *p;
	if (heap.toStart == NULL) {

		p = heap.fromFree;
		if (20 + sizeof(int) * length > heap.to - heap.fromFree) {
		printf("\t\tBeforce Heap_From=%dbyte Heap_To=%dbyte\n",(heap.fromFree-heap.from),(heap.toNext - heap.to));
			(heap.toStart == heap.to)?(bt = ((float)(heap.fromFree-heap.from) / (float)heap.size) *100):
			(bt = ((float)(heap.toNext-heap.to) / (float)heap.size) *100);

		heap.toNext = heap.toStart = heap.to;
			Tiger_gc();
			
			
			p = heap.toNext;
			printf("\n\t\tLast Heap_From=%dbyte Heap_To=%dbyte\n",(heap.fromFree-heap.from),(heap.toNext - heap.to));
			bt = ((float)(heap.toNext-heap.to) / (float)heap.size) *100;
			printf("\t\tTO Busy = %0.3f%%\n\t\tFrom->->->->->->GC...->->->->->->To\n",bt);
		}
		if (20 + sizeof(int) * length > heap.to + heap.size - heap.toNext) {
			printf("right ARRAY OutOfMemory!\n");
		
			exit(1);
		}
	} else if (heap.toStart == heap.to) {

		p = heap.toNext;
		if (20 + sizeof(int) * length > heap.to + heap.size - heap.toNext) {
		printf("\t\tBeforce Heap_From=%dbyte Heap_To=%dbyte\n",(heap.fromFree-heap.from),(heap.toNext - heap.to));
			(heap.toStart == heap.to)?(bt = ((float)(heap.fromFree-heap.from) / (float)heap.size) *100):
			(bt = ((float)(heap.toNext-heap.to) / (float)heap.size) *100);
		
			heap.toStart = NULL;
			heap.fromFree = heap.from;
			Tiger_gc();
	
			
			p = heap.fromFree;
				printf("\n\t\tLast Heap_From=%dbyte Heap_TO=%dbyte\n",(heap.fromFree-heap.from),(heap.toNext - heap.to));
			(bt = ((float)(heap.fromFree-heap.from) / (float)heap.size) *100);
			printf("\t\tFrom Busy = %0.3f%%\n\t\tTo->->->->->->->GC...->->->->->From\n",bt);
		}
		if (20 + sizeof(int) * length > heap.to - heap.fromFree) {
			printf("left ARRAY OutOfMemory!\n");
			exit(1);
		}
	}

	//memset(p, 0, 20 + sizeof(int) * length);
	((int*) p)[0] = NULL;
	((int*) p)[1] = 1;
	((int*) p)[2] = length;
	((int*) p)[3] = NULL;
	((int*) p)[4] = (heap.toStart == heap.to)?(heap.toNext+20):(heap.fromFree+20);

	(heap.toStart == NULL) ?
			(heap.fromFree += 20 + sizeof(int) * length) :
			(heap.toNext += 20 + sizeof(int) * length);
	return p;
}

//===============================================================//
// The Gimple Garbage Collector

// Lab 4, exercise 12:
// A copying collector based-on Cheney's algorithm.
static void Tiger_gc() {
		
	// Your code here:
	int * p = prev;//p is the top pointer of the stack
	LARGE_INTEGER m_liPerfFreq={0};	//获取每秒多少CPU PerFromance Tick 
	QueryPerformanceFrequency(&m_liPerfFreq); 
	LARGE_INTEGER linkTableStart={0};
	QueryPerformanceCounter(&linkTableStart);
      while(p != 0)
	{
		removeLocalObject(p);//try to move all local references
		removeFromalObject(p);//try to move all Fromal reference
		//printCurrentHeap(); //watch the current heap state after collection
		p = p[0];
	}
		LARGE_INTEGER linkTableNow={0};		
	QueryPerformanceCounter(&linkTableNow);
	int timer=TestTime(linkTableStart, linkTableNow, m_liPerfFreq);
	printf("\t\t\tTime : %d ms",timer);
	if(heap.toStart == heap.to)
	{
		heap.fromFree = heap.from; //after gc,clean up the other hemiHeap
	}
	else
	{
		heap.toNext = heap.to;//as above
	}
}

void removeLocalObject(int *p)//try to move all local references
{
	int i;
	for(i = 0; i < atoi(p[3]); i++)
	{
		move(p[4 + i]);//move local references according to the counts of local_gc_map
	}
}

void removeFromalObject(int* p)//try to move all Fromal reference
{

	char* c = p[1];
	int i;
	for(i = 0; i < strlen(c); i++)
	{
		if( c[i] == '1')
		{
			int *q = p[2] + 4 * i;
			int *a = *q;
			move(a);//move all Fromal references according to the '1' element of Fromal_gc_map vector
		}
	}


}




void printCurrentHeap()//watch the current heap state after collection
{
	if(heap.toStart == NULL)
	printf("leftHeap% = %.2f\n", 100 * (float)(heap.fromFree - heap.from)/(float)heap.size);
	else
	printf("rightHeap% = %.2f\n",  100 * (float)(heap.toNext - heap.to)/(float)heap.size);
}



void move(int *p)
{ 
	int i;
	if(p == NULL || p[3] != NULL || (p[1] != 0 && p[1] != 1))
		return;
	
	int *temp = p[0];//vtable_map
	char* classmap;
	if(temp != NULL)
{
	classmap = temp[0];
}

	int basicsize = 4;
	int realsize = 0;
	if(p[1] == 1)
	{
		realsize = (basicsize + 1 + p[3]) * 4;//array object
	}
	if(p[1] == 0)
	{
		if(classmap[0] == '2')
		{
		realsize = basicsize * 4;
		}		
		else
		{
		realsize = (strlen(temp[0]) + basicsize) * 4;//normal object
		}
		
	}

	if(heap.toStart == NULL)
	{
	
		memcpy(heap.fromFree, p, realsize);
		p = p[3] = heap.fromFree;
		heap.fromFree += realsize;
		//heap.toStart = NULL;
		if(temp == NULL) return;
		for(i = 0; i < strlen(classmap); i++) //to the current object ,move its referents tuple
	{
		if( classmap[i] == '1')
		{
			int *q = p[4 + i];
			move(q);
		}
	}

	}
	if(heap.toStart == heap.to)
	{
	int i;
		memcpy(heap.toNext, p, realsize);
		p = p[3] = heap.toNext;//forward is not null now!
		heap.toNext += realsize;
		if(temp ==NULL)return;
		for(i = 0; i < strlen(classmap); i++) //to the current object ,move its referents tuple
	{
		if( classmap[i] == '1')
		{
			int *q = p[4 + i];
			move(q);
		}
	}
	
	}
		
	return;
	
}
int TestTime(LARGE_INTEGER linkTableStart, LARGE_INTEGER linkTableNow, LARGE_INTEGER m_liPerfFreq)
{
	return ( ((linkTableNow.QuadPart - linkTableStart.QuadPart) * 1000)/m_liPerfFreq.QuadPart);
}










  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值