[kaffe] CVS kaffe (hkraemer): fixed mem leak in garbage collector

Kaffe CVS Kaffe Mailing List <kaffe@kaffe.org>
Fri Aug 22 04:44:02 2003


PatchSet 3971 
Date: 2003/08/22 11:42:13
Author: hkraemer
Branch: HEAD
Tag: (none) 
Log:
fixed mem leak in garbage collector

Members: 
	ChangeLog:1.1568->1.1569 
	kaffe/kaffevm/mem/gc-incremental.c:1.66->1.67 
	kaffe/kaffevm/mem/gc-mem.c:1.45->1.46 

Index: kaffe/ChangeLog
diff -u kaffe/ChangeLog:1.1568 kaffe/ChangeLog:1.1569
--- kaffe/ChangeLog:1.1568	Fri Aug 22 09:02:39 2003
+++ kaffe/ChangeLog	Fri Aug 22 11:42:13 2003
@@ -1,3 +1,13 @@
+2003-08-22  Helmer Kraemer  <hkraemer@freenet.de>
+
+	* kaffe/kaffevm/mem/gc-mem.c:
+	(gc_heap_free) properly free empty primitive blocks
+
+	* kaffe/kaffevm/mem/gc-incremental.c:
+	(gcWalkMemory, startGC, gcMan, finishGC,gcMalloc,createGC)
+	manage objects that have a finalizer and objects that don't
+	have one in different white and black lists
+	
 2003-08-22  Dalibor Topic <robilad@kaffe.org>,
 
 	* libraries/javalib/Klasses.jar.bootstrap:
Index: kaffe/kaffe/kaffevm/mem/gc-incremental.c
diff -u kaffe/kaffe/kaffevm/mem/gc-incremental.c:1.66 kaffe/kaffe/kaffevm/mem/gc-incremental.c:1.67
--- kaffe/kaffe/kaffevm/mem/gc-incremental.c:1.66	Sat Jul 26 16:50:51 2003
+++ kaffe/kaffe/kaffevm/mem/gc-incremental.c	Fri Aug 22 11:42:15 2003
@@ -47,11 +47,12 @@
 Hjava_lang_Thread* garbageman;
 static Hjava_lang_Thread* finalman;
 
-static gcList gclists[5];
-static const int mustfree = 4;		/* temporary list */
-static const int white = 3;
-static const int grey = 2;
-static const int black = 1;
+static gcList gclists[6];
+static const int nofin_white = 5;
+static const int fin_white = 4;
+static const int grey = 3;
+static const int nofin_black = 2;
+static const int fin_black = 1;
 static const int finalise = 0;
 
 static int gc_init = 0;
@@ -430,8 +431,26 @@
 	info = GCMEM2BLOCK(unit);
 	idx = GCMEM2IDX(info, unit);
 
+	if (GC_GET_COLOUR(info, idx) == GC_COLOUR_BLACK) {
+		return;
+	}
+
 	UREMOVELIST(unit);
-	UAPPENDLIST(gclists[black], unit);
+
+	/* if the object is about to be finalized, put it directly
+	 * into the finalise list, otherwise put it into the black
+	 * list.
+	 */
+	if (GC_GET_STATE(info, idx) == GC_STATE_INFINALIZE) {
+		gcStats.finalobj += 1;
+		gcStats.finalmem += GCBLOCKSIZE(info);
+		UAPPENDLIST(gclists[finalise], unit);
+	} else if (GC_GET_STATE(info, idx) == GC_STATE_NEEDFINALIZE) {
+		UAPPENDLIST(gclists[fin_black], unit);
+	} else {
+		UAPPENDLIST(gclists[nofin_black], unit);
+	}
+	
 	GC_SET_COLOUR(info, idx, GC_COLOUR_BLACK);
 
 	assert(GC_GET_FUNCS(info, idx) < 
@@ -474,7 +493,6 @@
 gcMan(void* arg)
 {
 	gc_unit* unit;
-	gc_unit* nunit;
 	gc_block* info;
 	int idx;
 	Collector *gcif = (Collector*)arg;
@@ -554,27 +572,33 @@
 		    
 		startGC(gcif);
 
-		for (unit = gclists[grey].cnext; unit != &gclists[grey]; unit = gclists[grey].cnext) {
+		/* process any objects found by walking the root references */
+		while (gclists[grey].cnext != &gclists[grey]) {
+			unit = gclists[grey].cnext;
 			gcWalkMemory(gcif, UTOMEM(unit));
 		}
+
 		/* Now walk any white objects which will be finalized.  They
 		 * may get reattached, so anything they reference must also
 		 * be live just in case.
 		 */
-		for (unit = gclists[white].cnext; unit != &gclists[white]; unit = nunit) {
-			nunit = unit->cnext;
+		while (gclists[fin_white].cnext != &gclists[fin_white]) {
+			unit = gclists[fin_white].cnext;
 			info = GCMEM2BLOCK(unit);
 			idx = GCMEM2IDX(info, unit);
-			if (GC_GET_STATE(info, idx) == GC_STATE_NEEDFINALIZE) {
-				/* this assert is somewhat expensive */
-				DBG(GCDIAG,
-				    assert(gc_heap_isobject(info, unit)));
-				GC_SET_STATE(info, idx, GC_STATE_INFINALIZE);
-				markObjectDontCheck(unit, info, idx);
-			}
+		
+			assert (GC_GET_STATE(info, idx) == GC_STATE_NEEDFINALIZE);
+
+			/* this assert is somewhat expensive */
+			DBG(GCDIAG,
+			    assert(gc_heap_isobject(info, unit)));
+			GC_SET_STATE(info, idx, GC_STATE_INFINALIZE);
+			markObjectDontCheck(unit, info, idx);
 		}
-		/* We may now have more grey objects, so walk them */
-		for (unit = gclists[grey].cnext; unit != &gclists[grey]; unit = gclists[grey].cnext) {
+
+		/* now process the objects that are referenced by objects to be finalized */
+		while (gclists[grey].cnext != &gclists[grey]) {
+			unit = gclists[grey].cnext;
 			gcWalkMemory(gcif, UTOMEM(unit));
 		}
 
@@ -639,7 +663,6 @@
 startGC(Collector *gcif)
 {
 	gc_unit* unit;
-	gc_unit* nunit;
 
 	gcStats.freedmem = 0;
 	gcStats.freedobj = 0;
@@ -663,9 +686,8 @@
 	startTiming(&gc_time, "gctime-scan");
 
 	/* Walk all objects on the finalizer list */
-	for (unit = gclists[finalise].cnext;
-	     unit != &gclists[finalise]; unit = nunit) {
-		nunit = unit->cnext;
+	while (gclists[finalise].cnext != &gclists[finalise]) {
+		unit = gclists[finalise].cnext;
 		gcMarkObject(gcif, UTOMEM(unit));
 	}
 
@@ -685,31 +707,57 @@
 	gc_unit* unit;
 	gc_block* info;
 	int idx;
+	gcList   toRemove;
+	int i;
 
 	/* There shouldn't be any grey objects at this point */
 	assert(gclists[grey].cnext == &gclists[grey]);
 
+	if (gclists[nofin_white].cnext != &gclists[nofin_white]) {
+		toRemove.cnext = gclists[nofin_white].cnext;
+		toRemove.cprev = gclists[nofin_white].cprev;
+
+		toRemove.cnext->cprev = &toRemove;
+		toRemove.cprev->cnext = &toRemove;
+
+		URESETLIST(gclists[nofin_white]);
+	} else {
+		URESETLIST(toRemove);
+	}	
+
+	stopTiming(&gc_time);
+	
+	RESUMEWORLD();
+
 	/* 
-	 * Any white objects should now be freed, but we cannot call
-	 * gc_heap_free here because we might block in gc_heap_free, 
-	 * which would leave the white list unprotected.
-	 * So we move them to a 'mustfree' list from where we'll pull them
-	 * off later.
-	 *
-	 * XXX: this is so silly it hurts.  Jason has a fix.
+	 * Now move the black objects back to the white queue for next time.
 	 */
-	while (gclists[white].cnext != &gclists[white]) {
-		unit = gclists[white].cnext;
-		UREMOVELIST(unit);
+	for (i=1; i<3; i++) {
+		while (gclists[i].cnext != &gclists[i]) {
+			unit = gclists[i].cnext;
+			UREMOVELIST(unit);
+
+			info = GCMEM2BLOCK(unit);
+			idx = GCMEM2IDX(info, unit);
+
+			assert(GC_GET_COLOUR(info, idx) == GC_COLOUR_BLACK);
+
+			UAPPENDLIST(gclists[i+3], unit);
+
+			GC_SET_COLOUR(info, idx, GC_COLOUR_WHITE);
+		}
+	}
 
+	startTiming(&sweep_time, "gctime-sweep");
+
+	while (toRemove.cnext != &toRemove) {
+		destroy_func_t destroy;
+		unit = toRemove.cnext; 
 		info = GCMEM2BLOCK(unit);
 		idx = GCMEM2IDX(info, unit);
 
-		assert(GC_GET_COLOUR(info, idx) == GC_COLOUR_WHITE);
-		assert(GC_GET_STATE(info, idx) == GC_STATE_NORMAL);
 		gcStats.freedmem += GCBLOCKSIZE(info);
 		gcStats.freedobj += 1;
-		UAPPENDLIST(gclists[mustfree], unit);
 		OBJECTSTATSREMOVE(unit);
 
 #if defined(ENABLE_JVMPI)
@@ -722,45 +770,24 @@
 			jvmpiPostEvent(&ev);
 		}
 #endif
-	}
-
-	/* 
-	 * Now move the black objects back to the white queue for next time.
-	 * Note that all objects that were eligible for finalization are now
-	 * black - this is so because we marked and then walked them.
-	 * We recognize them by their "INFINALIZE" state, however, and put
-	 * them on the finalise list.
-	 */
-	while (gclists[black].cnext != &gclists[black]) {
-		unit = gclists[black].cnext;
-		UREMOVELIST(unit);
 
+		/* invoke destroy function before freeing the object */
 		info = GCMEM2BLOCK(unit);
 		idx = GCMEM2IDX(info, unit);
-
-		assert(GC_GET_COLOUR(info, idx) == GC_COLOUR_BLACK);
-
-		if (GC_GET_STATE(info, idx) == GC_STATE_INFINALIZE) {
-			gcStats.finalmem += GCBLOCKSIZE(info);
-			gcStats.finalobj += 1;
-			UAPPENDLIST(gclists[finalise], unit);
-		}
-		else {
-			UAPPENDLIST(gclists[white], unit);
+		destroy = gcFunctions[GC_GET_FUNCS(info,idx)].destroy;
+		if (destroy != 0) {
+			destroy(gcif, UTOMEM(unit));
 		}
-		GC_SET_COLOUR(info, idx, GC_COLOUR_WHITE);
-	}
 
-	/* this is where we'll stop locking out other threads 
-	 * measure gc time until here.  This is not quite accurate, as
-	 * it excludes the time to sweep objects, but lacking
-	 * per-thread timing it's a reasonable thing to do.
-	 */
-	stopTiming(&gc_time);
+		UREMOVELIST(unit);
+		addToCounter(&gcgcablemem, "gcmem-gcable objects", 1, 
+			-((jlong)GCBLOCKSIZE(info)));
+		gc_heap_free(unit);
+	}
 
 #if defined(ENABLE_JVMPI)
 	if( JVMPI_EVENT_ISENABLED(JVMPI_EVENT_GC_FINISH) )
-	{
+	{ 
 		JVMPI_Event ev;
 
 		ev.event_type = JVMPI_EVENT_GC_FINISH;
@@ -771,35 +798,6 @@
 	}
 #endif
 
-	/* 
-	 * Now that all lists that the mutator manipulates are in a
-	 * consistent state, we can reenable the mutator here 
-	 */
-	RESUMEWORLD();
-
-	/* 
-	 * Now free the objects.  We can block here since we're the only
-	 * thread manipulating the "mustfree" list.
-	 */
-	startTiming(&sweep_time, "gctime-sweep");
-
-	while (gclists[mustfree].cnext != &gclists[mustfree]) {
-		destroy_func_t destroy;
-		unit = gclists[mustfree].cnext;
-
-		/* invoke destroy function before freeing the object */
-		info = GCMEM2BLOCK(unit);
-		idx = GCMEM2IDX(info, unit);
-		destroy = gcFunctions[GC_GET_FUNCS(info,idx)].destroy;
-		if (destroy != 0) {
-			destroy(gcif, UTOMEM(unit));
-		}
-
-		UREMOVELIST(unit);
-		addToCounter(&gcgcablemem, "gcmem-gcable objects", 1, 
-			-((jlong)GCBLOCKSIZE(info)));
-		gc_heap_free(unit);
-	}
 	stopTiming(&sweep_time);
 }
 
@@ -1063,7 +1061,12 @@
 		 * compiler to not delay computing mem by defining it volatile.
 		 */
 		GC_SET_COLOUR(info, i, GC_COLOUR_WHITE);
-		UAPPENDLIST(gclists[white], unit);
+
+		if (GC_GET_STATE(info, i) == GC_STATE_NEEDFINALIZE) {
+			UAPPENDLIST(gclists[fin_white], unit);
+		} else {
+			UAPPENDLIST(gclists[nofin_white], unit);
+		}
 	}
 	if (!reserve) {
 		reserve = gc_primitive_reserve();
@@ -1388,11 +1391,12 @@
 createGC(void (*_walkRootSet)(Collector*))
 {
 	walkRootSet = _walkRootSet;
-	URESETLIST(gclists[white]);
+	URESETLIST(gclists[nofin_white]);
+	URESETLIST(gclists[fin_white]);
 	URESETLIST(gclists[grey]);
-	URESETLIST(gclists[black]);
+	URESETLIST(gclists[nofin_black]);
+	URESETLIST(gclists[fin_black]);
 	URESETLIST(gclists[finalise]);
-	URESETLIST(gclists[mustfree]);
 	gc_obj.collector.ops = &GC_Ops;
 	return (&gc_obj.collector);
 }
Index: kaffe/kaffe/kaffevm/mem/gc-mem.c
diff -u kaffe/kaffe/kaffevm/mem/gc-mem.c:1.45 kaffe/kaffe/kaffevm/mem/gc-mem.c:1.46
--- kaffe/kaffe/kaffevm/mem/gc-mem.c:1.45	Tue Jul  8 07:33:50 2003
+++ kaffe/kaffe/kaffevm/mem/gc-mem.c	Fri Aug 22 11:42:15 2003
@@ -445,12 +445,13 @@
 			for (;*finfo;) {
 				if (*finfo == info) {
 					(*finfo) = info->next;
-					info->size = gc_pgsize;
-					gc_primitive_free(info);
 					break;
 				}
 				finfo = &(*finfo)->next;
 			}
+
+			info->size = gc_pgsize;
+			gc_primitive_free(info);
 		} else if (info->avail==1) {
 			/*
 			 * If this block contains no free sub-blocks yet, attach