diff --git a/src/array.c b/src/array.c
index 88237a175e8e906b39eecc25f4d0906f5374404b..b5dc886fb85f370a55f94a1f5afbeda9714dfab9 100644
--- a/src/array.c
+++ b/src/array.c
@@ -27,7 +27,6 @@ struct array empty_array=
   0,                     /* malloced Size = 0 */
   0,                     /* no types */
   T_MIXED,                 /* mixed array */
-  0,                     /* no flags */
 };
 
 
@@ -61,7 +60,6 @@ struct array *low_allocate_array(INT32 size,INT32 extra_space)
 
   v->malloced_size=size+extra_space;
   v->size=size;
-  v->flags=0;
   v->refs=1;
   v->prev=&empty_array;
   v->next=empty_array.next;
@@ -1286,69 +1284,64 @@ void check_all_arrays()
 
 #ifdef GC2
 
-void gc_check_array(struct array *a)
+void gc_mark_array_as_referenced(struct array *a)
 {
-  if(a == gc_ptr) gc_refs++;
-  if(a->flags & GC_MARK) return;
-  a->flags |= GC_MARK;
-  if(!(a->type_field & BIT_COMPLEX)) return;
-  gc_check_svalues(ITEM(a), a->size);
+  if(gc_mark(a))
+    if(a->type_field & BIT_COMPLEX)
+      gc_mark_svalues(ITEM(a), a->size);
 }
 
-
 void gc_check_all_arrays()
 {
-  struct array *a,*n;
-
+  struct array *a;
   a=&empty_array;
   do
   {
-    if(!(a->flags & GC_MARK) && a->type_field & BIT_COMPLEX)
-    {
-      gc_ptr=a;
-      gc_refs=0;
-      
-      gc_check_array(a);
-      
-      a->refs++;
-      
-      if(gc_refs == a->refs)
-      {
-	/* This structure contains as many references to itself as
-	 * it has referenes, which means that it is circular and
-	 * should be destroyed, so please go away.
-	 */
-	
-	free_svalues(ITEM(a), a->size, a->type_field);
-	
-	a->size=0;
-	
-      }
-      
-      if(!(n=a->next))
-	fatal("Null pointer in array list.\n");
-      
-      free_array(a);
-      a=n;
-    }else{
-      a=a->next;
-    }
+    if(a->type_field & BIT_COMPLEX)
+      gc_check_svalues(ITEM(a), a->size);
+
+    a=a->next;
   } while (a != & empty_array);
 }
 
-void gc_clear_array_marks()
+
+void gc_mark_all_arrays()
 {
   struct array *a;
 
   a=&empty_array;
   do
   {
-    a->flags &=~ GC_MARK;
+    if(gc_is_referenced(a))
+      gc_mark_array_as_referenced(a);
+            
     a=a->next;
-
   } while (a != & empty_array);
 }
 
+void gc_free_all_unreferenced_arrays()
+{
+  struct array *a,*next;
+
+  a=&empty_array;
+  do
+  {
+    if(gc_do_free(a))
+    {
+      a->refs++;
+      free_svalues(ITEM(a), a->size, a->type_field);
+      a->size=0;
+
+      if(!(next=a->next))
+	fatal("Null pointer in array list.\n");
+
+      free_array(a);
+      a=next;
+    }else{
+      a=a->next;
+    }
+  } while (a != & empty_array);
+}
 
 
 #endif /* GC2 */
diff --git a/src/array.h b/src/array.h
index a0a058021fe3dcb413cf160fe71e71f5c4c84f5d..526120e763bb0347544710534ecf42c3ebe2020f 100644
--- a/src/array.h
+++ b/src/array.h
@@ -20,11 +20,12 @@ struct array
 			 * Bits can be set that don't exist in the array
 			 * though.
 			 */
-  INT16 flags;		/* flags, like gc_cycle */
   struct svalue item[1];
 };
 
 
+extern struct array empty_array;
+
 #define ITEM(X) ((X)->item)
 
 /* These are arguments for the function 'merge' which merges two sorted
@@ -120,9 +121,10 @@ void array_replace(struct array *a,
 		   struct svalue *to);
 void check_array(struct array *a);
 void check_all_arrays();
-void gc_check_array(struct array *a);
+void gc_mark_array_as_referenced(struct array *a);
 void gc_check_all_arrays();
-void gc_clear_array_marks();
+void gc_mark_all_arrays();
+void gc_free_all_unreferenced_arrays();
 /* Prototypes end here */
 
 
diff --git a/src/gc.c b/src/gc.c
index d4f1cf812d7640d458615d891acda4241f40e0ee..4e86c01b2e992b6c653a31c03353e4f0ccc057ab 100644
--- a/src/gc.c
+++ b/src/gc.c
@@ -7,6 +7,13 @@
 #include "global.h"
 
 #ifdef GC2
+
+#include "array.h"
+#include "list.h"
+#include "mapping.h"
+#include "object.h"
+#include "program.h"
+
 #include "gc.h"
 #include "main.h"
 
@@ -17,10 +24,10 @@
 
 #define GC_CONST 20
 #define MIN_ALLOC_THRESHOLD 1000
+#defien MAX_ALLOC_THRESHOLD 10000000
 #define MULTIPLIER 0.9
+#define MARKER_CHUNK_SIZE 1023
 
-void *gc_ptr;
-INT32 gc_refs;
 INT32 num_objects;
 INT32 num_allocs;
 INT32 alloc_threshold = MIN_ALLOC_THRESHOLD;
@@ -28,10 +35,143 @@ INT32 alloc_threshold = MIN_ALLOC_THRESHOLD;
 static double objects_alloced;
 static double objects_freed;
 
+#define GC_REFERENCED 1
+
+struct marker
+{
+  struct marker *next;
+  void *marked;
+  INT32 refs;
+  INT32 flags;
+};
+
+struct marker_chunk
+{
+  struct marker_chunk *next;
+  struct marker markers[MARKER_CHUNK_SIZE];
+};
+
+static struct marker_chunk *chunk=0;
+static int markers_left_in_chunk=0;
+
+static struct marker *new_marker()
+{
+  if(!markers_left_in_chunk)
+  {
+    struct marker_chunk *m;
+    m=(struct marker_chunk *)xalloc(sizeof(struct marker_chunk));
+    m->next=chunk;
+    chunk=m;
+    markers_left_in_chunk=MARKER_CHUNK_SIZE;
+  }
+  markers_left_in_chunk--;
+
+  return chunk->markers + markers_left_in_chunk;
+}
+
+static struct marker **hash=0;
+static int hashsize=0;
+
+static struct marker *getmark(void *a)
+{
+  int hashval;
+  struct marker *m;
+
+  hashval=((long)a)%hashsize;
+
+  for(m=hash[hashval];m;m=m->next)
+    if(m->marked == a)
+      return m;
+
+  m=new_marker();
+  m->marked=a;
+  m->refs=0;
+  m->flags=0;
+  m->next=hash[hashval];
+  hash[hashval]=m;
+
+  return m;
+}
+
+void gc_check(void *a)
+{
+  getmark(a)->refs++;
+}
+
+int gc_is_referenced(void *a)
+{
+  struct marker *m;
+  m=getmark(a);
+#ifdef DEBUG
+  if(m->refs > *(INT32 *)a)
+    fatal("Ref counts are totally wrong!!!\n");
+#endif
+  return m->refs < *(INT32 *)a;
+}
+
+int gc_mark(void *a)
+{
+  struct marker *m;
+  m=getmark(a);
+
+  if(m->flags & GC_REFERENCED)
+  {
+    return 0;
+  }else{
+    m->flags |= GC_REFERENCED;
+    return 1;
+  }
+}
+
+int gc_do_free(void *a)
+{
+  struct marker *m;
+  m=getmark(a);
+  return !(m->flags & GC_REFERENCED);
+}
+
+/* Not all of these are primes, but they should be adequate */
+static INT32 hashprimes[] =
+{
+  31,        /* ~ 2^0  = 1 */
+  31,        /* ~ 2^1  = 2 */
+  31,        /* ~ 2^2  = 4 */
+  31,        /* ~ 2^3  = 8 */
+  31,        /* ~ 2^4  = 16 */
+  31,        /* ~ 2^5  = 32 */
+  61,        /* ~ 2^6  = 64 */
+  127,       /* ~ 2^7  = 128 */
+  251,       /* ~ 2^8  = 256 */
+  541,       /* ~ 2^9  = 512 */
+  1151,      /* ~ 2^10 = 1024 */
+  2111,      /* ~ 2^11 = 2048 */
+  4327,      /* ~ 2^12 = 4096 */
+  8803,      /* ~ 2^13 = 8192 */
+  17903,     /* ~ 2^14 = 16384 */
+  32321,     /* ~ 2^15 = 32768 */
+  65599,     /* ~ 2^16 = 65536 */
+  133153,    /* ~ 2^17 = 131072 */
+  270001,    /* ~ 2^18 = 264144 */
+  547453,    /* ~ 2^19 = 524288 */
+  1109891,   /* ~ 2^20 = 1048576 */
+  2000143,   /* ~ 2^21 = 2097152 */
+  4561877,   /* ~ 2^22 = 4194304 */
+  9248339,   /* ~ 2^23 = 8388608 */
+  16777215,  /* ~ 2^24 = 16777216 */
+  33554431,  /* ~ 2^25 = 33554432 */
+  67108863,  /* ~ 2^26 = 67108864 */
+  134217727, /* ~ 2^27 = 134217728 */
+  268435455, /* ~ 2^28 = 268435456 */
+  536870911, /* ~ 2^29 = 536870912 */
+  1073741823,/* ~ 2^30 = 1073741824 */
+  2147483647,/* ~ 2^31 = 2147483648 */
+};
+
 void do_gc()
 {
   double tmp;
   INT32 tmp2;
+  struct marker_chunk *m;
 
   tmp2=num_objects;
 
@@ -45,14 +185,45 @@ void do_gc()
   
   objects_freed*=MULTIPLIER;
   objects_freed += (double) num_objects;
-  
-  gc_clear_array_marks();
-  gc_clear_object_marks();
-  gc_clear_program_marks();
+
+
+  /* init hash , hashsize will be a prime between num_objects/8 and
+   * num_objects/4, this will assure that no re-hashing is needed.
+   */
+  hashsize=my_log2(num_objects);
+  hashsize-=2;
+  if(hashsize<0) hashsize=0;
+  hashsize=hashprimes[hashsize];
+  hash=(struct marker **)xalloc(sizeof(struct marker **)*hashsize);
+  MEMSET((char *)hash,0,sizeof(struct marker **)*hashsize);
+  markers_left_in_chunk=0;
   
   gc_check_all_arrays();
+  gc_check_all_lists();
+  gc_check_all_mappings();
   gc_check_all_programs();
   gc_check_all_objects();
+
+  gc_mark_all_arrays();
+  gc_mark_all_lists();
+  gc_mark_all_mappings();
+  gc_mark_all_programs();
+  gc_mark_all_objects();
+
+  gc_free_all_unreferenced_arrays();
+  gc_free_all_unreferenced_lists();
+  gc_free_all_unreferenced_mappings();
+  gc_free_all_unreferenced_programs();
+  gc_free_all_unreferenced_objects();
+
+
+  /* Free hash table */
+  free((char *)hash);
+  while(m=chunk)
+  {
+    chunk=m->next;
+    free((char *)m);
+  }
   
   objects_freed -= (double) num_objects;
 
@@ -76,14 +247,6 @@ void do_gc()
 	    (long)(tmp2-num_objects),(long)tmp2);
 #endif
 }
-#endif
-
-
-
-
-
-
-
-
 
+#endif
 
diff --git a/src/gc.h b/src/gc.h
index 96746616ea256836fadab7f71b2dad092f349115..cffbd118c245a927357070cdb2cd4071af049bf6 100644
--- a/src/gc.h
+++ b/src/gc.h
@@ -5,15 +5,12 @@
 
 #include "types.h"
 
-extern void *gc_ptr;
-extern INT32 gc_refs;
 extern INT32 num_objects;
 extern INT32 num_allocs;
 extern INT32 alloc_threshold;
 
 #define GC_ALLOC() do{ num_objects++; if(++num_allocs > alloc_threshold) do_gc(); } while(0);
 #define GC_FREE() num_objects--
-#define GC_MARK 1
 
 #else
 
@@ -24,6 +21,12 @@ extern INT32 alloc_threshold;
 #endif
 
 /* Prototypes begin here */
+struct marker;
+struct marker_chunk;
+void gc_check(void *a);
+int gc_is_referenced(void *a);
+int gc_mark(void *a);
+int gc_do_free(void *a);
 void do_gc();
 /* Prototypes end here */
 
diff --git a/src/list.c b/src/list.c
index c2a968482e2861846a9d3448e53f36de49ddcac3..8975acc4645ee39a3556555bd6156810a67b4a44 100644
--- a/src/list.c
+++ b/src/list.c
@@ -14,6 +14,7 @@
 #include "dynamic_buffer.h"
 #include "interpret.h"
 #include "builtin_efuns.h"
+#include "gc.h"
 
 struct list *first_list;
 
@@ -28,6 +29,7 @@ int list_member(struct list *l, struct svalue *ind)
 static struct list *allocate_list(struct array *ind)
 {
   struct list *l;
+  GC_ALLOC();
   l=ALLOC_STRUCT(list);
   l->next = first_list;
   l->prev = 0;
@@ -56,6 +58,7 @@ void really_free_list(struct list *l)
   if(first_list == l) first_list = 0;
 
   free((char *)l);
+  GC_FREE();
 }
 
 static void order_list(struct list *l)
@@ -247,7 +250,7 @@ struct list *copy_list_recursively(struct list *l,
     }
   }
 
-  ret=allocate_list(0);
+  ret=allocate_list( & empty_array );
   doing.pointer_b=(void *)ret;
 
   ret->ind=copy_array_recursively(l->ind,&doing);
@@ -256,3 +259,49 @@ struct list *copy_list_recursively(struct list *l,
 
   return ret;
 }
+
+
+#ifdef GC2
+
+void gc_mark_list_as_referenced(struct list *l)
+{
+  if(gc_mark(l))
+    gc_mark_array_as_referenced(l->ind);
+}
+
+void gc_check_all_lists()
+{
+  struct list *l;
+  for(l=first_list;l;l=l->next)
+    gc_check(l->ind);
+}
+
+void gc_mark_all_lists()
+{
+  struct list *l;
+  for(l=first_list;l;l=l->next)
+    if(gc_is_referenced(l))
+      gc_mark_list_as_referenced(l);
+}
+
+void gc_free_all_unreferenced_lists()
+{
+  struct list *l,*next;
+
+  for(l=first_list;l;l=next)
+  {
+    if(gc_do_free(l))
+    {
+      l->refs++;
+      free_svalues(ITEM(l->ind), l->ind->size, l->ind->type_field);
+      l->ind->size=0;
+      next=l->next;
+
+      free_list(l);
+    }else{
+      next=l->next;
+    }
+  }
+}
+
+#endif /* GC2 */
diff --git a/src/list.h b/src/list.h
index da66aaee93295d90456dfbf9e9d79755cc97908e..e072f0af66ac65748b1846d8d6db2815ca7941b5 100644
--- a/src/list.h
+++ b/src/list.h
@@ -37,6 +37,10 @@ node * make_node_from_list(struct list *l);
 void f_aggregate_list(INT32 args);
 struct list *copy_list_recursively(struct list *l,
 				   struct processing *p);
+void gc_mark_list_as_referenced(struct list *l);
+void gc_check_all_lists();
+void gc_mark_all_lists();
+void gc_free_all_unreferenced_lists();
 /* Prototypes end here */
 
 #endif
diff --git a/src/mapping.c b/src/mapping.c
index b23d2bdff5355ca6e7f97728164d7932547e0f35..5f566a0cc8e6be3ef444452412bbf60b07097d52 100644
--- a/src/mapping.c
+++ b/src/mapping.c
@@ -14,6 +14,7 @@
 #include "memory.h"
 #include "dynamic_buffer.h"
 #include "interpret.h"
+#include "gc.h"
 
 struct mapping *first_mapping;
 
@@ -67,6 +68,7 @@ void mapping_index(struct svalue *dest,
 static struct mapping *allocate_mapping(struct array *ind, struct array *val)
 {
   struct mapping *m;
+  GC_ALLOC();
   m=ALLOC_STRUCT(mapping);
   m->next = first_mapping;
   m->prev = 0;
@@ -97,6 +99,8 @@ void really_free_mapping(struct mapping *m)
   if(first_mapping == m) first_mapping = 0;
 
   free((char *)m);
+
+  GC_FREE();
 }
 
 static void order_mapping(struct mapping *m)
@@ -369,7 +373,7 @@ struct mapping *copy_mapping_recursively(struct mapping *m,
     }
   }
 
-  ret=allocate_mapping(0,0);
+  ret=allocate_mapping(&empty_array, &empty_array);
   doing.pointer_b=(void *)ret;
 
   ret->ind=copy_array_recursively(m->ind,&doing);
@@ -436,3 +440,57 @@ void check_all_mappings()
     check_mapping(m);
 }
 #endif
+
+
+#ifdef GC2
+
+void gc_mark_mapping_as_referenced(struct mapping *m)
+{
+  if(gc_mark(m))
+  {
+    gc_mark_array_as_referenced(m->ind);
+    gc_mark_array_as_referenced(m->val);
+  }
+}
+
+void gc_check_all_mappings()
+{
+  struct mapping *m;
+  for(m=first_mapping;m;m=m->next)
+  {
+    gc_check(m->ind);
+    gc_check(m->val);
+  }
+}
+
+void gc_mark_all_mappings()
+{
+  struct mapping *m;
+  for(m=first_mapping;m;m=m->next)
+    if(gc_is_referenced(m))
+      gc_mark_mapping_as_referenced(m);
+}
+
+void gc_free_all_unreferenced_mappings()
+{
+  struct mapping *m,*next;
+
+  for(m=first_mapping;m;m=next)
+  {
+    if(gc_do_free(m))
+    {
+      m->refs++;
+      free_svalues(ITEM(m->ind), m->ind->size, m->ind->type_field);
+      free_svalues(ITEM(m->val), m->val->size, m->val->type_field);
+      m->ind->size=0;
+      m->val->size=0;
+      next=m->next;
+
+      free_mapping(m);
+    }else{
+      next=m->next;
+    }
+  }
+}
+
+#endif /* GC2 */
diff --git a/src/mapping.h b/src/mapping.h
index 8eb88ae8732822dc959257a27dc4e08e5ad00f81..8132d4cae5edcb581ac7b681d93bcc31d20076e7 100644
--- a/src/mapping.h
+++ b/src/mapping.h
@@ -55,5 +55,9 @@ void mapping_search_no_free(struct svalue *to,
 			    struct svalue *start);
 void check_mapping(struct mapping *m);
 void check_all_mappings();
+void gc_mark_mapping_as_referenced(struct mapping *m);
+void gc_check_all_mappings();
+void gc_mark_all_mappings();
+void gc_free_all_unreferenced_mappings();
 /* Prototypes end here */
 #endif
diff --git a/src/object.c b/src/object.c
index 86174658e9593168b002d1de02bcc8480135464f..e61c203dcda7ebfc683bb3b6b2d761078f66c8ce 100644
--- a/src/object.c
+++ b/src/object.c
@@ -644,45 +644,83 @@ struct array *object_values(struct object *o)
 
 void gc_check_object(struct object *o)
 {
-  INT32 e;
-  if(o == gc_ptr) gc_refs++;
-  if(o->flags & GC_MARK) return;
-  o->flags |= GC_MARK;
-
-  if(!o->prog) return;
+}
 
-  for(e=0;e<(int)o->prog->num_identifier_indexes;e++)
+void gc_mark_object_as_referenced(struct object *o)
+{
+  if(gc_mark(o))
   {
-    struct identifier *i;
-    
-    i=ID_FROM_INT(o->prog, e);
-
-    if(i->flags & IDENTIFIER_FUNCTION) continue;
-
-    if(i->run_time_type == T_MIXED)
+    if(o->prog)
     {
-      gc_check_svalues((struct svalue *)LOW_GET_GLOBAL(o,e,i),1);
-    }else{
-      gc_check_short_svalue((union anything *)LOW_GET_GLOBAL(o,e,i),
-			    i->run_time_type);
+      INT32 e;
+      
+      for(e=0;e<(int)o->prog->num_identifier_indexes;e++)
+      {
+	struct identifier *i;
+	
+	i=ID_FROM_INT(o->prog, e);
+	
+	if(i->flags & IDENTIFIER_FUNCTION) continue;
+	
+	if(i->run_time_type == T_MIXED)
+	{
+	  gc_mark_svalues((struct svalue *)LOW_GET_GLOBAL(o,e,i),1);
+	}else{
+	  gc_mark_short_svalue((union anything *)LOW_GET_GLOBAL(o,e,i),
+			       i->run_time_type);
+	}
+      }
     }
   }
 }
 
 void gc_check_all_objects()
 {
-  struct object *o, *next;
+  struct object *o;
+  for(o=first_object;o;o=o->next)
+  {
+    if(o->prog)
+    {
+      INT32 e;
+
+      for(e=0;e<(int)o->prog->num_identifier_indexes;e++)
+      {
+	struct identifier *i;
+	
+	i=ID_FROM_INT(o->prog, e);
+	
+	if(i->flags & IDENTIFIER_FUNCTION) continue;
+	
+	if(i->run_time_type == T_MIXED)
+	{
+	  gc_check_svalues((struct svalue *)LOW_GET_GLOBAL(o,e,i),1);
+	}else{
+	  gc_check_short_svalue((union anything *)LOW_GET_GLOBAL(o,e,i),
+				i->run_time_type);
+	}
+      }
+    }
+  }
+}
+
+void gc_mark_all_objects()
+{
+  struct object *o;
+  for(o=first_object;o;o=o->next)
+    if(gc_is_referenced(o))
+      gc_mark_object_as_referenced(o);
+}
+
+void gc_free_all_unreferenced_objects()
+{
+  struct object *o,*next;
+
   for(o=first_object;o;o=next)
   {
-    if(!(o->flags & GC_MARK))
+    if(gc_do_free(o))
     {
-      gc_ptr=o;
-      gc_refs=0;
-      
       o->refs++;
-      
-      if(gc_refs == o->refs) destruct(o);
-      
+      destruct(o);
       next=o->next;
       free_object(o);
     }else{
@@ -691,11 +729,5 @@ void gc_check_all_objects()
   }
 }
 
-void gc_clear_object_marks()
-{
-  struct object *o;
-
-  for(o=first_object;o;o=o->next) o->flags &=~ GC_MARK;
-}
-
 #endif /* GC2 */
+
diff --git a/src/object.h b/src/object.h
index 32608e56ed1024f3e9f0caa00ee2d7c8b3802238..e4bb8cd0dd2360cfa1c55991163221e03b387bde 100644
--- a/src/object.h
+++ b/src/object.h
@@ -14,9 +14,6 @@
 struct object
 {
   INT32 refs;                    /* Reference count, must be first. */
-#ifdef GC2
-  INT16 flags;
-#endif
   struct program *prog;
   struct object *next;
   struct object *prev;
@@ -63,8 +60,10 @@ void cleanup_objects();
 struct array *object_indices(struct object *o);
 struct array *object_values(struct object *o);
 void gc_check_object(struct object *o);
+void gc_mark_object_as_referenced(struct object *o);
 void gc_check_all_objects();
-void gc_clear_object_marks();
+void gc_mark_all_objects();
+void gc_free_all_unreferenced_objects();
 /* Prototypes end here */
 
 #endif /* OBJECT_H */
diff --git a/src/program.c b/src/program.c
index 85de0f4f961d7ac359d02faba3b4d28f4c29ceba..ec2f5f944259d07834406a11384213eb70d021e2 100644
--- a/src/program.c
+++ b/src/program.c
@@ -1303,31 +1303,37 @@ void cleanup_program()
 
 #ifdef GC2
 
-void gc_check_program(struct program *p)
+void gc_mark_program_as_referenced(struct program *p)
 {
-  if(p==gc_ptr) gc_refs++;
-  if(p->flags & GC_MARK) return;
-  p->flags |= GC_MARK;
-  gc_check_svalues(p->constants, p->num_constants);
+  if(gc_mark(p))
+    gc_mark_svalues(p->constants, p->num_constants);
 }
 
 void gc_check_all_programs()
 {
-  struct program *p, *next;
+  struct program *p;
+  for(p=first_program;p;p=p->next)
+    gc_check_svalues(p->constants, p->num_constants);
+}
+
+void gc_mark_all_programs()
+{
+  struct program *p;
+  for(p=first_program;p;p=p->next)
+    if(gc_is_referenced(p))
+      gc_mark_program_as_referenced(p);
+}
+
+void gc_free_all_unreferenced_programs()
+{
+  struct program *p,*next;
+
   for(p=first_program;p;p=next)
   {
-    if(!(p->flags & GC_MARK))
+    if(gc_do_free(p))
     {
-      gc_ptr=p;
-      gc_refs=0;
-
-      gc_check_program(p);
-      
       p->refs++;
-      
-      if(gc_refs == p->refs)
-	free_svalues(p->constants, p->num_constants, -1);
-      
+      free_svalues(p->constants, p->num_constants, -1);
       next=p->next;
       free_program(p);
     }else{
@@ -1336,11 +1342,4 @@ void gc_check_all_programs()
   }
 }
 
-void gc_clear_program_marks()
-{
-  struct program *p;
-
-  for(p=first_program;p;p=p->next) p->flags &=~ GC_MARK;
-}
-
 #endif /* GC2 */
diff --git a/src/program.h b/src/program.h
index fe1c265aab35c35d732104281544b06c8e80ae27..b8a8fed9fdd4d7274050be83c7dc76048338f5a1 100644
--- a/src/program.h
+++ b/src/program.h
@@ -93,7 +93,6 @@ struct inherit
 struct program
 {
   INT32 refs;
-  INT32 flags;
   INT32 id;             /* used to identify program in caches */
   INT32 storage_needed; /* storage needed in the object struct */
 
@@ -182,9 +181,10 @@ struct program *end_c_program(char *name);
 void add_function(char *name,void (*cfun)(INT32),char *type,INT16 flags);
 void check_all_programs();
 void cleanup_program();
-void gc_check_program(struct program *p);
+void gc_mark_program_as_referenced(struct program *p);
 void gc_check_all_programs();
-void gc_clear_program_marks();
+void gc_mark_all_programs();
+void gc_free_all_unreferenced_programs();
 /* Prototypes end here */
 
 
diff --git a/src/svalue.c b/src/svalue.c
index 6793c90527bf8e231fe64010267aa287e77d3ff1..58b8d82b81637dbeb145fdad58929d88552686e0 100644
--- a/src/svalue.c
+++ b/src/svalue.c
@@ -641,23 +641,24 @@ void gc_check_svalues(struct svalue *s, int num)
   {
     switch(s->type)
     {
-    case T_ARRAY: gc_check_array(s->u.array); break;
-    case T_LIST:
-      gc_check_array(s->u.list->ind);
-      break;
-    case T_MAPPING:
-      gc_check_array(s->u.mapping->ind);
-      gc_check_array(s->u.mapping->val);
-      break;
+    case T_FUNCTION:
+      if(s->subtype == -1) break;
+
     case T_OBJECT:
       if(s->u.object->prog)
       {
-	gc_check_object(s->u.object);
+	gc_check(s->u.object);
       }else{
 	free_svalue(s);
       }
       break;
-    case T_PROGRAM: gc_check_program(s->u.program); break;
+
+    case T_PROGRAM:
+    case T_ARRAY:
+    case T_LIST:
+    case T_MAPPING:
+      gc_check(s->u.refs);
+      break;
     }
   }
 }
@@ -667,21 +668,69 @@ void gc_check_short_svalue(union anything *u, TYPE_T type)
   if(!u->refs) return;
   switch(type)
   {
-  case T_ARRAY: gc_check_array(u->array); break;
-  case T_LIST: gc_check_array(u->list->ind); break;
+  case T_OBJECT:
+    if(u->object->prog)
+    {
+      gc_check(u->object);
+    }else{
+      free_short_svalue(u,T_OBJECT);
+    }
+    break;
+
+  case T_ARRAY:
+  case T_LIST:
   case T_MAPPING:
-    gc_check_array(u->mapping->ind);
-    gc_check_array(u->mapping->val);
+  case T_PROGRAM:
+    gc_check(u->refs);
     break;
+  }
+}
+
+void gc_mark_svalues(struct svalue *s, int num)
+{
+  INT32 e;
+  for(e=0;e<num;e++,s++)
+  {
+    switch(s->type)
+    {
+    case T_ARRAY:   gc_mark_array_as_referenced(s->u.array);     break;
+    case T_LIST:    gc_mark_list_as_referenced(s->u.list);       break;
+    case T_MAPPING: gc_mark_mapping_as_referenced(s->u.mapping); break;
+    case T_PROGRAM: gc_mark_program_as_referenced(s->u.program); break;
+
+    case T_FUNCTION:
+      if(s->subtype == -1) break;
+
+    case T_OBJECT:
+      if(s->u.object->prog)
+      {
+	gc_mark_object_as_referenced(s->u.object);
+      }else{
+	free_svalue(s);
+      }
+      break;
+    }
+  }
+}
+
+void gc_mark_short_svalue(union anything *u, TYPE_T type)
+{
+  if(!u->refs) return;
+  switch(type)
+  {
+  case T_ARRAY:   gc_mark_array_as_referenced(u->array);     break;
+  case T_LIST:    gc_mark_list_as_referenced(u->list);       break;
+  case T_MAPPING: gc_mark_mapping_as_referenced(u->mapping); break;
+  case T_PROGRAM: gc_mark_program_as_referenced(u->program); break;
+
   case T_OBJECT:
     if(u->object->prog)
     {
-      gc_check_object(u->object);
+      gc_mark_object_as_referenced(u->object);
     }else{
       free_short_svalue(u,T_OBJECT);
     }
     break;
-  case T_PROGRAM: gc_check_program(u->program); break;
   }
 }
 #endif /* GC2 */