[Gc] Changes requested to reduce GC heap growth on Windows

Derek McUmber derek.mcumber at datamtnsol.com
Mon Jan 26 20:18:07 PST 2004


Attached is a small diff of required changes for gc compiled with the 
MSFT family of C compilers.  Please review this request and check for
correctness.  I have tested this on WinXP/2K/2KAdvanced/win98 and it
appears to be satisfactory.

The issue is with statements like:

	while ( 0 == h && GET_MEM()) {
		h = GC_allochblk(...);
	}

The microsoft compilers do not optimize the execution by not calling
the right side of the && expression if the left side is true (vc98 and
vc7).  This leads to double heap growth which is not desirable.

thanks
-------------- next part --------------
diff -r libgc/allchblk.c libgc2/allchblk.c
553a554,558
>     if (flags == IGNORE_OFF_PAGE) {
> 	/* GC_printf0("flags == IGNORE_OFF_PAGE\n"); */	
>     } else {
> 	flags = IGNORE_OFF_PAGE;
>     }
586c591,593
< 	    if (size_avail < size_needed) continue;
---
> 	    if (size_avail < size_needed) {
> 		continue;
> 	    }
736c743
<     	if (!GC_install_counts(hbp, (word)size_needed)) return(0);
---
>     	if (!GC_install_counts(hbp, (word)size_needed)) { GC_printf0("may be leaking memory\n"); return(0); }
diff -r libgc/alloc.c libgc2/alloc.c
234c234,245
<     return(GC_adj_words_allocd() >= min_words_allocd());
---
>     word adj_allocd = GC_adj_words_allocd();
>     word min_reqd = min_words_allocd();
> #   ifdef CONDPRINT
>     if (GC_print_stats) {
> 	GC_printf2(
> 	    "***>Checking Adj Words allocated %ld >= %ld allocd bytes\n",
>      		  (long)WORDS_TO_BYTES(adj_allocd),
> 	   	  (long)WORDS_TO_BYTES(min_reqd));
> 	      }
> #           endif
> 
>     return(adj_allocd >= min_reqd);
287a299
> 
322,323c334
< 	GC_printf0(
< 	    "GC_try_to_collect_inner: finishing collection in progress\n");
---
> 	GC_printf0("GC_try_to_collect_inner: finishing collection in progress\n");
891a903,910
> #	ifdef CONDPRINT
> 	  if (GC_print_stats) {
> 	GC_printf1(
> 	    "Inside expand_hp_inner for %ld hblocks\n",
> 	   	  (long)WORDS_TO_BYTES(n));
> 	  }
> #       endif
> 
892a912
> 
978a999,1004
> #   ifdef CONDPRINT
>       if (GC_print_stats) {
>    		GC_printf0("Starting GC_collect_or_expand\n");
> 	}
> #   endif
> 
984a1011,1012
> 
>       /* word blocks_to_get = 3 * needed_blocks; */
1001,1003c1029,1037
<       if (!GC_expand_hp_inner(blocks_to_get)
<         && !GC_expand_hp_inner(needed_blocks)) {
<       	if (GC_fail_count++ < GC_max_retries) {
---
> #   ifdef CONDPRINT
>       if (GC_print_stats) {
>    	GC_printf2("Inside GC_collect_or_expand:expand part %lu blocks to get %lu is needed\n",
> 	(long)WORDS_TO_BYTES(blocks_to_get), (long)WORDS_TO_BYTES(needed_blocks));
> 	}
> #   endif
>       if (!GC_expand_hp_inner(blocks_to_get)) {
>         if (!GC_expand_hp_inner(needed_blocks)) {
>           if (GC_fail_count++ < GC_max_retries) {
1005,1009c1039,1043
< 	    GC_gcollect_inner();
< 	} else {
< #	    if !defined(AMIGA) || !defined(GC_AMIGA_FASTALLOC)
< 	      WARN("Out of Memory!  Returning NIL!\n", 0);
< #	    endif
---
> 	    	    GC_gcollect_inner();
> 	    } else {
> #   if !defined(AMIGA) || !defined(GC_AMIGA_FASTALLOC)
> 	        WARN("Out of Memory!  Returning NIL!\n", 0);
> #   endif
1011c1045,1046
< 	}
---
> 	    }
> 	  }/* end NEEDED_BLOCKS */
1018,1019c1053,1056
<       }
<     }
---
>       }/* end BLOCKS_TO_GET */
>     }/* end if !GC_Incremental */
> 
> 
diff -r libgc/malloc.c libgc2/malloc.c
51a52
> 
59,60c60,86
<     while (0 == h && GC_collect_or_expand(n_blocks, (flags != 0))) {
< 	h = GC_allochblk(lw, k, flags);
---
> 
>     if (0 == h) {
> #	ifdef CONDPRINT
> 	  if (GC_print_stats) {
> 		GC_printf0("Previous allochblk returned 0, calling collect_or_expand\n");
> 		/* this number on windows is 4 x 384 (from gc_priv.h) and we must be careful
> 		   not to run out of Heap Sects which is about 1532 */
> 		GC_printf1("MAX_HEAP_SECT: %lu\n", (long)WORDS_TO_BYTES(MAX_HEAP_SECTS));
> 	  }
> #	endif
> 
> 	/* try and grow the heap only as much as necessary, looping could cause OS crash. 
> 	   previous while (0 == h && GC_collect_or_expand(n_blocks, (flags != 0))) would
> 	   increase the heap a minimum of 2x: first when above allochblk failed and second
> 	   to test the success of the allochblk in the loop.  Some compilers may optimize
> 	   out the right side of the && statement, but msft vc98 and vc7 compilers do not */
>     	while (0 == h) {
> 		/* Windows OS's will deny memory if the OS is doing management at this time
> 		   the collect_or_expand will increase the size it asks for during each loop
> 		   and this will grow heap considerably when unnecessary.  I add the sleep
> 		   to give the OS time to finish its work and the number of loops drops to
> 		   2 to 4 from 10 to 15 (which loop * 8meg = 120meg in some instances) */
> 		Sleep(10);
> 		GC_printf0("retry allocation of memory\n");
> 		GC_collect_or_expand(n_blocks, (flags != 0));
> 		h = GC_allochblk(lw, k, flags);
> 	}
62c88,90
<     if (h == 0) {
---
> 
>     /* if h is 0 here, then we were unable to GET_MEM from the OS. */
>     if (0 == h) {


More information about the Gc mailing list