NOTE: This patch has been committed.
Usually, mc-alloc allocates large blocks of memory ("heap sections")
from the operating system and manages these sections. If memory
becomes short, such large blocks may not be available. What then
usually happens, is that XEmacs prints "memory full" in a loop.
With this patch, the allocator is informed about memory shortage and
then allocates only the needed pages and no larger blocks. This may
keep XEmacs alive until the garbage collector can free enough memory
and recovers from the memory exhaustion. If the recovery is not
pssible, XEmacs aborts rather than printing "memory full" in a loop.
src/ChangeLog addition:
2006-03-26 Marcus Crestani <crestani(a)xemacs.org>
* alloc.c (malloc_warning): Move function into scope of
MALLOC_END, add MALLOC_END.
* alloc.c (memory_full): Add memory shortage indication, adjust
error messages.
* mc-alloc.c: Add memory_shortage.
* mc-alloc.c (expand_heap): If memory is short, allocate only the
needed pages, not more.
* mc-alloc.h: Add memory_shortage.
manual-newgc-xemacs-21.5 source patch:
Diff command: cvs -q diff -u
Files affected: src/mc-alloc.h src/mc-alloc.c src/alloc.c
Index: src/alloc.c
===================================================================
RCS file: /pack/xemacscvs/XEmacs/xemacs/src/alloc.c,v
retrieving revision 1.124
diff -u -r1.124 alloc.c
--- src/alloc.c 26 Mar 2006 14:33:38 -0000 1.124
+++ src/alloc.c 26 Mar 2006 14:45:34 -0000
@@ -231,46 +231,6 @@
}
#endif /* not NEW_GC */
-/* malloc calls this if it finds we are near exhausting storage */
-void
-malloc_warning (const char *str)
-{
- if (ignore_malloc_warnings)
- return;
-
- warn_when_safe
- (Qmemory, Qemergency,
- "%s\n"
- "Killing some buffers may delay running out of memory.\n"
- "However, certainly by the time you receive the 95%% warning,\n"
- "you should clean up, kill this Emacs, and start a new one.",
- str);
-}
-
-/* Called if malloc returns zero */
-DOESNT_RETURN
-memory_full (void)
-{
- fprintf (stderr, "##### M E M O R Y F U L L #####\n");
- /* Force a GC next time eval is called.
- It's better to loop garbage-collecting (we might reclaim enough
- to win) than to loop beeping and barfing "Memory exhausted"
- */
- consing_since_gc = gc_cons_threshold + 1;
- recompute_need_to_garbage_collect ();
-#ifndef NEW_GC
- release_breathing_space ();
-#endif /* not NEW_GC */
-
- /* Flush some histories which might conceivably contain garbalogical
- inhibitors. */
- if (!NILP (Fboundp (Qvalues)))
- Fset (Qvalues, Qnil);
- Vcommand_history = Qnil;
-
- out_of_memory ("Memory exhausted", Qunbound);
-}
-
static void
set_alloc_mins_and_maxes (void *val, Bytecount size)
{
@@ -352,6 +312,66 @@
if (!val && size != 0)
memory_full ();
set_alloc_mins_and_maxes (val, size);
+}
+
+/* malloc calls this if it finds we are near exhausting storage */
+void
+malloc_warning (const char *str)
+{
+ if (ignore_malloc_warnings)
+ return;
+
+ /* Remove the malloc lock here, because warn_when_safe may allocate
+ again. It is safe to remove the malloc lock here, because malloc
+ is already finished (malloc_warning is called via
+ after_morecore_hook -> check_memory_limits -> save_warn_fun ->
+ malloc_warning). */
+ MALLOC_END ();
+
+ warn_when_safe
+ (Qmemory, Qemergency,
+ "%s\n"
+ "Killing some buffers may delay running out of memory.\n"
+ "However, certainly by the time you receive the 95%% warning,\n"
+ "you should clean up, kill this Emacs, and start a new one.",
+ str);
+}
+
+/* Called if malloc returns zero */
+DOESNT_RETURN
+memory_full (void)
+{
+ /* Force a GC next time eval is called.
+ It's better to loop garbage-collecting (we might reclaim enough
+ to win) than to loop beeping and barfing "Memory exhausted"
+ */
+ consing_since_gc = gc_cons_threshold + 1;
+ recompute_need_to_garbage_collect ();
+#ifdef NEW_GC
+ /* Put mc-alloc into memory shortage mode. This may keep XEmacs
+ alive until the garbage collector can free enough memory to get
+ us out of the memory exhaustion. If already in memory shortage
+ mode, we are in a loop and hopelessly lost. */
+ if (memory_shortage)
+ {
+ fprintf (stderr, "Memory full, cannot recover.\n");
+ ABORT ();
+ }
+ fprintf (stderr,
+ "Memory full, try to recover.\n"
+ "You should clean up, kill this Emacs, and start a new one.\n");
+ memory_shortage++;
+#else /* not NEW_GC */
+ release_breathing_space ();
+#endif /* not NEW_GC */
+
+ /* Flush some histories which might conceivably contain garbalogical
+ inhibitors. */
+ if (!NILP (Fboundp (Qvalues)))
+ Fset (Qvalues, Qnil);
+ Vcommand_history = Qnil;
+
+ out_of_memory ("Memory exhausted", Qunbound);
}
/* like malloc, calloc, realloc, free but:
Index: src/mc-alloc.c
===================================================================
RCS file: /pack/xemacscvs/XEmacs/xemacs/src/mc-alloc.c,v
retrieving revision 1.9
diff -u -r1.9 mc-alloc.c
--- src/mc-alloc.c 26 Mar 2006 14:05:30 -0000 1.9
+++ src/mc-alloc.c 26 Mar 2006 14:45:35 -0000
@@ -411,6 +411,8 @@
/* MC Allocator */
/************************************************************************/
+/* Set to 1 if memory becomes short. */
+EMACS_INT memory_shortage;
/*--- misc functions ---------------------------------------------------*/
@@ -1136,9 +1138,12 @@
void *real_start;
/* determine number of pages the heap should grow */
- n_pages = needed_pages + (HEAP_SIZE / (PAGE_SIZE * HEAP_GROWTH_DIVISOR));
- if (n_pages < MIN_HEAP_INCREASE)
- n_pages = MIN_HEAP_INCREASE;
+ if (memory_shortage)
+ n_pages = needed_pages;
+ else
+ n_pages = max (MIN_HEAP_INCREASE,
+ needed_pages
+ + (HEAP_SIZE / (PAGE_SIZE * HEAP_GROWTH_DIVISOR)));
/* get the real values */
real_size = (n_pages * PAGE_SIZE) + PAGE_SIZE;
Index: src/mc-alloc.h
===================================================================
RCS file: /pack/xemacscvs/XEmacs/xemacs/src/mc-alloc.h,v
retrieving revision 1.5
diff -u -r1.5 mc-alloc.h
--- src/mc-alloc.h 26 Mar 2006 14:05:30 -0000 1.5
+++ src/mc-alloc.h 26 Mar 2006 14:45:35 -0000
@@ -27,6 +27,8 @@
BEGIN_C_DECLS
+/* Set to 1 if memory becomes short. */
+extern EMACS_INT memory_shortage;
/* Internal Allocator Functions: */
--
Marcus