This is the mail archive of the libc-alpha@sourceware.org mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Ping: [PATCH v2] Allow shrinking of arena heaps using mmap based onovercommit settings when available


Hi,

Ping: the original discussion is here:

http://sourceware.org/ml/libc-alpha/2012-08/msg00462.html

I've attached an updated patch as well with the typo that Rich Felker
caught.

The current implementation of heap shrinking in malloc arenas uses
madvise for non-setuid programs to let the kernel know that the tail
of the arena is not needed. This is ineffective on Linux when
overcommit_memory is set to 2 and an explicit munmap is required to
drop the pages from the process' commit charge. This is already done
for setuid programs by calling mmap on the tail region to be dropped
with MAP_FIXED set and the protection of the region set to PROT_NONE,
so this patch adds a Linux specific override that checks for the value
of the overcommit_memory sysctl to decide between mmap and madvise.
madvise is retained as the default for other cases since it has a clear
performance advantage for multithreaded processes. The original
submission above has more specific details.

Regards,
Siddhesh

ChangeLog:

	* malloc/arena.c: Include malloc-sysdep.h.
	(shrink_heap): Use check_may_shrink_heap to decide if madvise
	is sufficient to shrink the heap or an unmap is needed.
	* sysdeps/generic/malloc-sysdep.h: New file.  Define
	new function check_may_shrink_heap.
	* sysdeps/unix/sysv/linux/malloc-sysdep.h: New file.  Define
	new function check_may_shrink_heap.
diff --git a/malloc/arena.c b/malloc/arena.c
index 9e5e332..480491b 100644
--- a/malloc/arena.c
+++ b/malloc/arena.c
@@ -20,6 +20,9 @@
 
 #include <stdbool.h>
 
+/* Get the implementation for check_may_shrink_heap.  */
+#include <malloc-sysdep.h>
+
 /* Compile-time constants.  */
 
 #define HEAP_MIN_SIZE (32*1024)
@@ -622,9 +625,9 @@ shrink_heap(heap_info *h, long diff)
   new_size = (long)h->size - diff;
   if(new_size < (long)sizeof(*h))
     return -1;
-  /* Try to re-map the extra heap space freshly to save memory, and
-     make it inaccessible. */
-  if (__builtin_expect (__libc_enable_secure, 0))
+  /* Try to re-map the extra heap space freshly to save memory, and make it
+     inaccessible.  See malloc-sysdep.h to know when this is true.  */
+  if (__builtin_expect (check_may_shrink_heap (), 0))
     {
       if((char *)MMAP((char *)h + new_size, diff, PROT_NONE,
 		      MAP_FIXED) == (char *) MAP_FAILED)
diff --git a/sysdeps/generic/malloc-sysdep.h b/sysdeps/generic/malloc-sysdep.h
new file mode 100644
index 0000000..4ea85aa
--- /dev/null
+++ b/sysdeps/generic/malloc-sysdep.h
@@ -0,0 +1,28 @@
+/* System-specific implementations for some malloc support functions.
+
+   Copyright (C) 2012 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <unistd.h>
+
+/* Force an unmap on heap shrink for setuid programs.  This is so that the
+   kernel immediately drops the PTE for the mapping.  */
+static inline bool
+check_may_shrink_heap (void)
+{
+  return __libc_enable_secure;
+}
diff --git a/sysdeps/unix/sysv/linux/malloc-sysdep.h b/sysdeps/unix/sysv/linux/malloc-sysdep.h
new file mode 100644
index 0000000..be5c6d3
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/malloc-sysdep.h
@@ -0,0 +1,61 @@
+/* System-specific implementations for some malloc support functions.
+
+   Copyright (C) 2012 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <fcntl.h>
+#include <unistd.h>
+#include <not-cancel.h>
+
+/* The Linux kernel overcommits address space by default and if there is not
+   enough memory available, it uses various parameters to decide the process to
+   kill.  It is however possible to disable or curb this overcommit behaviour
+   by setting the proc sysctl vm.overcommit_memory to the value '2' and with
+   that, a process is only allowed to use the maximum of a pre-determined
+   fraction of the total address space.  In such a case, we want to make sure
+   that we are judicious with our heap usage as well, and explicitly give away
+   the freed top of the heap to reduce our commit charge.  See the proc(5) man
+   page to know more about overcommit behaviour.
+
+   Other than that, we also force an unmap for setuid programs.  */
+static inline bool
+check_may_shrink_heap (void)
+{
+  static int may_shrink_heap = -1;
+
+  if (__builtin_expect (may_shrink_heap >= 0, 1))
+    return may_shrink_heap;
+
+  may_shrink_heap = __libc_enable_secure;
+
+  if (__builtin_expect (may_shrink_heap, 0))
+    return may_shrink_heap;
+
+  int fd = open_not_cancel_2 ("/proc/sys/vm/overcommit_memory",
+			      O_RDONLY | O_CLOEXEC);
+
+  if (fd != -1)
+    {
+      char val = 0;
+      int n = read_not_cancel (fd, &val, 1);
+
+      may_shrink_heap = (n > 0 && val == '2');
+      close_not_cancel_no_status (fd);
+    }
+
+  return may_shrink_heap;
+}

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]