diff -urN Gauche-0.8.13.orig/src/core.c Gauche-0.8.13/src/core.c
--- Gauche-0.8.13.orig/src/core.c	2007-10-06 16:53:18.000000000 +0900
+++ Gauche-0.8.13/src/core.c	2008-04-17 03:28:54.000000000 +0900
@@ -39,6 +39,11 @@
 #include "gauche/paths.h"
 #include "gauche/builtin-syms.h"
 
+#ifdef GAUCHE_EXPERIMENTAL_GC_OOM_FN
+static void *oom_reserved_ptr = NULL;
+static ScmInternalMutex oom_mutex;
+#endif /* !GAUCHE_EXPERIMENTAL_GC_OOM_FN */
+
 /*
  * out-of-memory handler.  this will be called by GC.
  */
@@ -49,6 +54,38 @@
     return NULL;                /* dummy */
 }
 
+#ifdef GAUCHE_EXPERIMENTAL_GC_OOM_FN
+static GC_PTR oom_handler_survivable(size_t bytes)
+{
+    (void)SCM_INTERNAL_MUTEX_LOCK(oom_mutex);
+    if (oom_reserved_ptr == NULL) {
+        (void)SCM_INTERNAL_MUTEX_UNLOCK(oom_mutex);
+        return oom_handler(bytes);
+    }
+    GC_FREE(oom_reserved_ptr);
+    oom_reserved_ptr = NULL;
+    GC_gcollect();
+    (void)SCM_INTERNAL_MUTEX_UNLOCK(oom_mutex);
+    Scm_SysError("out of memory (%d)", bytes);
+    return NULL;                /* dummy */
+}
+
+/* this called by SCM_MALLOC() and SCM_MALLOC_ATOMIC() */
+void Scm_GCRecoverOOM(void)
+{
+    (void)SCM_INTERNAL_MUTEX_LOCK(oom_mutex);
+    if (
+            (oom_reserved_ptr == NULL)
+            &&
+            (SCM_OOM_THRESHOLD_SIZE <= GC_get_free_bytes())
+       ) {
+        oom_reserved_ptr =
+            GC_malloc_atomic_uncollectable(SCM_OOM_RESERVED_SIZE);
+    }
+    (void)SCM_INTERNAL_MUTEX_UNLOCK(oom_mutex);
+}
+#endif /* !GAUCHE_EXPERIMENTAL_GC_OOM_FN */
+
 /*
  * Features list used by cond-expand macro
  */
@@ -125,6 +162,16 @@
     GC_finalize_on_demand = TRUE;
     GC_finalizer_notifier = finalizable;
 
+#ifdef GAUCHE_EXPERIMENTAL_GC_OOM_FN
+    (void)SCM_INTERNAL_MUTEX_INIT(oom_mutex);
+    (void)SCM_INTERNAL_MUTEX_LOCK(oom_mutex);
+    if (oom_reserved_ptr == NULL) {
+        oom_reserved_ptr =
+            GC_malloc_atomic_uncollectable(SCM_OOM_RESERVED_SIZE);
+    }
+    (void)SCM_INTERNAL_MUTEX_UNLOCK(oom_mutex);
+#endif /* !GAUCHE_EXPERIMENTAL_GC_OOM_FN */
+
     (void)SCM_INTERNAL_MUTEX_INIT(cond_features.mutex);
 
     /* Initialize components.  The order is important, for some components
@@ -175,6 +222,11 @@
     /* a trick to make sure the gc thread object is linked */
     ptr_pthread_create = (int (*)(void))GC_pthread_create;
 #endif
+
+#ifdef GAUCHE_EXPERIMENTAL_GC_OOM_FN
+    /* this must be at after Scm__Init****() */
+    GC_oom_fn = oom_handler_survivable;
+#endif /* !GAUCHE_EXPERIMENTAL_GC_OOM_FN */
 }
 
 /*=============================================================
diff -urN Gauche-0.8.13.orig/src/gauche.h Gauche-0.8.13/src/gauche.h
--- Gauche-0.8.13.orig/src/gauche.h	2008-02-08 20:53:54.000000000 +0900
+++ Gauche-0.8.13/src/gauche.h	2008-04-17 02:44:43.000000000 +0900
@@ -115,7 +115,19 @@
 #define SCM_DEBUG_HELPER      TRUE
 #endif
 
+#ifdef GAUCHE_EXPERIMENTAL_GC_OOM_FN
+#ifndef SCM_OOM_RESERVED_SIZE
+/*
+ * TODO: decide by amount-of-memory at compile-time ?
+ */
+#define SCM_OOM_RESERVED_SIZE (64*1024)
+#define SCM_OOM_THRESHOLD_SIZE (SCM_OOM_RESERVED_SIZE * 2)
+#endif
+/* TODO: fix gauche/memory.h (and related), and be 1 */
+#define SCM_INLINE_MALLOC_PRIMITIVES 0
+#else /* !GAUCHE_EXPERIMENTAL_GC_OOM_FN */
 #define SCM_INLINE_MALLOC_PRIMITIVES 1
+#endif /* !GAUCHE_EXPERIMENTAL_GC_OOM_FN */
 
 #ifdef GAUCHE_USE_PTHREADS
 # include <gauche/pthread.h>
@@ -373,8 +385,16 @@
 #define SCM_INSTANCE_SLOTS(obj)  (SCM_INSTANCE(obj)->slots)
 
 /* Fundamental allocators */
+#ifdef GAUCHE_EXPERIMENTAL_GC_OOM_FN
+/* TODO: Scm_GCRecoverOOM to be replace macro (if possible) */
+#define SCM_MALLOC(size)          \
+    (Scm_GCRecoverOOM(), GC_MALLOC(size))
+#define SCM_MALLOC_ATOMIC(size)   \
+    (Scm_GCRecoverOOM(), GC_MALLOC_ATOMIC(size))
+#else /* !GAUCHE_EXPERIMENTAL_GC_OOM_FN */
 #define SCM_MALLOC(size)          GC_MALLOC(size)
 #define SCM_MALLOC_ATOMIC(size)   GC_MALLOC_ATOMIC(size)
+#endif /* !GAUCHE_EXPERIMENTAL_GC_OOM_FN */
 
 #define SCM_NEW(type)         ((type*)(SCM_MALLOC(sizeof(type))))
 #define SCM_NEW_ARRAY(type, nelts) ((type*)(SCM_MALLOC(sizeof(type)*(nelts))))
@@ -1662,6 +1682,10 @@
 SCM_EXTERN void *Scm_AddCleanupHandler(void (*proc)(void *data), void *data);
 SCM_EXTERN void  Scm_DeleteCleanupHandler(void *handle);
 
+#ifdef GAUCHE_EXPERIMENTAL_GC_OOM_FN
+SCM_EXTERN void Scm_GCRecoverOOM(void);
+#endif /* !GAUCHE_EXPERIMENTAL_GC_OOM_FN */
+
 /* repl */
 SCM_EXTERN void Scm_Repl(ScmObj reader, ScmObj evaluator, ScmObj printer,
                          ScmObj prompter);
