* [PATCH] Avoid fragmenting address space
@ 2004-03-18 10:13 Jakub Jelinek
0 siblings, 0 replies; only message in thread
From: Jakub Jelinek @ 2004-03-18 10:13 UTC (permalink / raw)
To: wg; +Cc: Glibc hackers
Hi!
For details see:
http://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=118574
If mmap addresses grow down (e.g. exec-shield has this property, sbrk grow
bottom up and mmap areas top down), but malloc is moreless the only user of
mmap for some time, new_heap will get already HEAP_MAX_SIZE aligned
chunks. Say:
0xb7500000
0xb7300000
0xb7100000
0xb6f00000
and always munmap the second 1MB. This leads to bad fragmentation.
The following (still untested) patch shouldn't be IMHO very costly and
fix up this situation. I think it doesn't need any locking, worst case
we'll try to mmap the same address (without MAP_FIXED) more than once.
2004-03-18 Jakub Jelinek <jakub@redhat.com>
* malloc/arena.c (aligned_heap_area): New variable.
(new_heap): If aligned_heap_area != NULL, attempt to use that
first. If HEAP_MAX_SIZE << 1 area is already HEAP_MAX_SIZE bytes
aligned, remember the second half in aligned_heap_area.
(delete_heap): Clear aligned_heap_area if deleting the area right
before aligned_heap_area.
--- libc/malloc/arena.c.jj 2003-07-15 17:04:36.000000000 +0200
+++ libc/malloc/arena.c 2004-03-18 10:57:21.034171230 +0100
@@ -550,6 +550,16 @@ dump_heap(heap) heap_info *heap;
#endif /* MALLOC_DEBUG > 1 */
+/* If consecutive mmap (0, HEAP_MAX_SIZE << 1, ...) calls return decreasing
+ addresses as opposed to increasing, new_heap would badly fragment the
+ address space. In that case remember the second HEAP_MAX_SIZE part
+ aligned to HEAP_MAX_SIZE from last mmap (0, HEAP_MAX_SIZE << 1, ...)
+ call (if it is already aligned) and try to reuse it next time. We need
+ no locking for it, as kernel ensures the atomicity for us - worst case
+ we'll call mmap (addr, HEAP_MAX_SIZE, ...) for some value of addr in
+ multiple threads, but only one will succeed. */
+static char *aligned_heap_area;
+
/* Create a new heap. size is automatically rounded up to a multiple
of the page size. */
@@ -580,21 +590,38 @@ new_heap(size, top_pad) size_t size, top
No swap space needs to be reserved for the following large
mapping (on Linux, this is the case for all non-writable mappings
anyway). */
- p1 = (char *)MMAP(0, HEAP_MAX_SIZE<<1, PROT_NONE, MAP_PRIVATE|MAP_NORESERVE);
- if(p1 != MAP_FAILED) {
- p2 = (char *)(((unsigned long)p1 + (HEAP_MAX_SIZE-1)) & ~(HEAP_MAX_SIZE-1));
- ul = p2 - p1;
- munmap(p1, ul);
- munmap(p2 + HEAP_MAX_SIZE, HEAP_MAX_SIZE - ul);
- } else {
- /* Try to take the chance that an allocation of only HEAP_MAX_SIZE
- is already aligned. */
- p2 = (char *)MMAP(0, HEAP_MAX_SIZE, PROT_NONE, MAP_PRIVATE|MAP_NORESERVE);
- if(p2 == MAP_FAILED)
- return 0;
- if((unsigned long)p2 & (HEAP_MAX_SIZE-1)) {
+ p2 = MAP_FAILED;
+ if(aligned_heap_area) {
+ p2 = (char *)MMAP(aligned_heap_area, HEAP_MAX_SIZE, PROT_NONE,
+ MAP_PRIVATE|MAP_NORESERVE);
+ aligned_heap_area = NULL;
+ if (p2 != MAP_FAILED && ((unsigned long)p2 & (HEAP_MAX_SIZE-1))) {
munmap(p2, HEAP_MAX_SIZE);
- return 0;
+ p2 = MAP_FAILED;
+ }
+ }
+ if(p2 == MAP_FAILED) {
+ p1 = (char *)MMAP(0, HEAP_MAX_SIZE<<1, PROT_NONE,
+ MAP_PRIVATE|MAP_NORESERVE);
+ if(p1 != MAP_FAILED) {
+ p2 = (char *)(((unsigned long)p1 + (HEAP_MAX_SIZE-1))
+ & ~(HEAP_MAX_SIZE-1));
+ ul = p2 - p1;
+ if (ul)
+ munmap(p1, ul);
+ else
+ aligned_heap_area = p2 + HEAP_MAX_SIZE;
+ munmap(p2 + HEAP_MAX_SIZE, HEAP_MAX_SIZE - ul);
+ } else {
+ /* Try to take the chance that an allocation of only HEAP_MAX_SIZE
+ is already aligned. */
+ p2 = (char *)MMAP(0, HEAP_MAX_SIZE, PROT_NONE, MAP_PRIVATE|MAP_NORESERVE);
+ if(p2 == MAP_FAILED)
+ return 0;
+ if((unsigned long)p2 & (HEAP_MAX_SIZE-1)) {
+ munmap(p2, HEAP_MAX_SIZE);
+ return 0;
+ }
}
}
if(mprotect(p2, size, PROT_READ|PROT_WRITE) != 0) {
@@ -644,7 +671,12 @@ grow_heap(h, diff) heap_info *h; long di
/* Delete a heap. */
-#define delete_heap(heap) munmap((char*)(heap), HEAP_MAX_SIZE)
+#define delete_heap(heap) \
+ do { \
+ if ((char *)(heap) + HEAP_MAX_SIZE == aligned_heap_area) \
+ aligned_heap_area = NULL; \
+ munmap((char*)(heap), HEAP_MAX_SIZE); \
+ } while (0)
static int
internal_function
Jakub
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2004-03-18 10:13 UTC | newest]
Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2004-03-18 10:13 [PATCH] Avoid fragmenting address space Jakub Jelinek
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).