[m-dev.] for review: fix memory leak

Fergus Henderson fjh at cs.mu.OZ.AU
Tue Oct 5 09:22:26 AEST 1999


Estimated hours taken: 16

Fix a problem where the compiler was leaking memory
when compiling more than one file a time.
Note that this fix solves that specific bug,
but does not address the problem in general.
(A more general fix would be for the garbage collector
to scan only the parts of the Mercury stacks which
are currently live, but this is trickier...)

The fix includes adding a new library module library/gc.m.

compiler/mercury_compile.m:
	If we're processing more than one module, then invoke garbage
	collection explicitly after processing each one.

library/gc.m:
	New module.  Currently this only contains one routine,
	`garbage_collect', which forces a garbage collection.
	This routine clears out the Mercury stacks and registers
	before invoking GC_gcollect().

	Eventually we might want to include a more extensive interface,
	including e.g. features to enable and disable collection, etc.
	(see boehm_gc/gc.h for a list of useful features).

runtime/mercury_regs.h:
	Add macro MR_clear_regs_for_GC(), for use by gc__garbage_collect.

runtime/mercury_memory_zones.h:
	Add macro MR_clear_zone_for_GC(), for use by gc__garbage_collect.

Workspace: /d-drive/home/hg/fjh/mercury
Index: compiler/mercury_compile.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/mercury_compile.m,v
retrieving revision 1.138
diff -u -r1.138 mercury_compile.m
--- compiler/mercury_compile.m	1999/09/14 02:52:35	1.138
+++ compiler/mercury_compile.m	1999/10/04 21:59:51
@@ -27,6 +27,7 @@
 	% library modules
 :- import_module int, list, map, set, std_util, dir, require, string, bool.
 :- import_module library, getopt, set_bbbtree, term, varset.
+:- import_module gc.
 
 	% the main compiler passes (mostly in order of execution)
 :- import_module handle_options, prog_io, prog_out, modules, module_qual.
@@ -126,6 +127,7 @@
 :- mode process_stdin_arg_list(in, out, di, uo) is det.
 
 process_stdin_arg_list(Modules0, Modules) -->
+	( { Modules0 \= [] } -> garbage_collect ; [] ),
 	io__read_line_as_string(FileResult),
 	( 
 		{ FileResult = ok(Line) },
@@ -156,6 +158,7 @@
 process_arg_list_2([], []) --> [].
 process_arg_list_2([Arg | Args], [Modules | ModulesList]) -->
 	process_arg(Arg, Modules), !,
+	( { Args \= [] } -> garbage_collect ; [] ),
 	process_arg_list_2(Args, ModulesList).
 
 	% Figure out whether the argument is a module name or a file name.
Index: library/gc.m
===================================================================
RCS file: gc.m
diff -N gc.m
--- /dev/null	Wed May  6 06:32:27 1998
+++ gc.m	Tue Oct  5 08:40:44 1999
@@ -0,0 +1,53 @@
+%---------------------------------------------------------------------------%
+% Copyright (C) 1999 The University of Melbourne.
+% This file may only be copied under the terms of the GNU Library General
+% Public License - see the file COPYING.LIB in the Mercury distribution.
+%---------------------------------------------------------------------------%
+%
+% File: gc.m.
+% Author: fjh.
+% Stability: medium.
+%
+% This module defines some procedures for controlling the actions
+% of the garbage collector.
+%
+% ---------------------------------------------------------------------------%
+% ---------------------------------------------------------------------------%
+
+:- module gc.
+:- interface.
+:- import_module io.
+
+	% Force a garbage collection.
+:- pred garbage_collect(io__state::di, io__state::uo) is det.
+
+	% Force a garbage collection.
+	% Note that this version is not really impure, but it needs to be
+	% declared impure to ensure that the compiler won't try to
+	% optimize it away.
+:- impure pred garbage_collect is det.
+
+%---------------------------------------------------------------------------%
+
+:- implementation.
+
+:- pragma promise_pure(garbage_collect/2).
+
+garbage_collect -->
+	{ impure garbage_collect }.
+
+:- pragma no_inline(garbage_collect/0).
+
+:- pragma c_code(garbage_collect, [will_not_call_mercury], "
+#ifdef CONSERVATIVE_GC
+	/* clear out the stacks and registers before garbage collecting */
+	MR_clear_zone_for_GC(MR_CONTEXT(detstack_zone), MR_sp + 1);
+	MR_clear_zone_for_GC(MR_CONTEXT(nondetstack_zone), MR_maxfr + 1);
+	MR_clear_regs_for_GC();
+
+	GC_gcollect();
+#endif
+").
+
+%---------------------------------------------------------------------------%
+%---------------------------------------------------------------------------%
Index: runtime/mercury_memory_zones.h
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_memory_zones.h,v
retrieving revision 1.4
diff -u -r1.4 mercury_memory_zones.h
--- runtime/mercury_memory_zones.h	1998/11/09 14:35:35	1.4
+++ runtime/mercury_memory_zones.h	1999/10/04 23:08:34
@@ -110,8 +110,31 @@
 	Word	*redzone;	/* beginning of the current redzone */
 	ZoneHandler *handler;   /* handler for page faults in the redzone */
 #endif /* MR_CHECK_OVERFLOW_VIA_MPROTECT */
+
+	/*
+	** MR_zone_end specifies the end of the 
+	** area accessible without a page fault.
+	** It is used by MR_clear_zone_for_GC().
+	*/
+#ifdef MR_CHECK_OVERFLOW_VIA_MPROTECT
+	#define MR_zone_end	redzone
+#elif defined(HAVE_MPROTECT)
+	#define MR_zone_end	hardmax
+#else
+	#define MR_zone_end	top
+#endif
 };
 
+/*
+** MR_clear_zone_for_GC(MemoryZone *zone, void *start_address):
+**	Zero out the (hopefully unused) portion of the zone
+**	from the specified `start_address' to the end of the zone.
+**	This is used to avoid unwanted memory retition due to 
+**	false hits in the conservative garbage collector.
+*/
+#define MR_clear_zone_for_GC(zone, start_address) \
+	((void) memset((start_address), 0, \
+		(char*)((zone)->MR_zone_end) - (char *)(start_address)))
 
 /*
 ** init_memory_arena() allocates (if necessary) the top-level memory pool
Index: runtime/mercury_regs.h
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_regs.h,v
retrieving revision 1.13
diff -u -r1.13 mercury_regs.h
--- runtime/mercury_regs.h	1999/04/20 11:48:15	1.13
+++ runtime/mercury_regs.h	1999/10/04 22:10:46
@@ -228,6 +228,22 @@
 #define MR_virtual_global_hp 		MR_saved_global_hp(MR_fake_reg)
 
 /*
+** MR_clear_regs_for_GC() clears all of the Mercury general-purpose
+** registers.  It is used to avoid unwanted memory retition due to
+** false hits in the conservative garbage collector.
+*/
+#define MR_clear_regs_for_GC()						\
+	do {								\
+		save_registers();					\
+		{ int i;						\
+		  for (i = 1; i <= MAX_VIRTUAL_REG; i++) {		\
+			virtual_reg(i) = 0;				\
+		  }							\
+		}							\
+		restore_registers();					\
+	} while (0)
+
+/*
 ** get_reg() and set_reg() provide a different way of addressing
 ** the registers; unlike virtual_reg(), you don't need to wrap them
 ** inside save_registers()/restore_regs() to copy the real regs to/from

-- 
Fergus Henderson <fjh at cs.mu.oz.au>  |  "I have always known that the pursuit
WWW: <http://www.cs.mu.oz.au/~fjh>  |  of excellence is a lethal habit"
PGP: finger fjh at 128.250.37.3        |     -- the last words of T. S. Garp.
--------------------------------------------------------------------------
mercury-developers mailing list
Post messages to:       mercury-developers at cs.mu.oz.au
Administrative Queries: owner-mercury-developers at cs.mu.oz.au
Subscriptions:          mercury-developers-request at cs.mu.oz.au
--------------------------------------------------------------------------



More information about the developers mailing list