]>
Commit | Line | Data |
---|---|---|
bb330e25 AF |
1 | commit 9fab36eb583c0e585e83a01253299afed9ea9a11 |
2 | Author: Siddhesh Poyarekar <siddhesh@redhat.com> | |
3 | Date: Tue Sep 25 14:10:29 2012 +0530 | |
4 | ||
5 | Shrink heap on linux when overcommit_memory == 2 | |
6 | ||
7 | Using madvise with MADV_DONTNEED to release memory back to the kernel | |
8 | is not sufficient to change the commit charge accounted against the | |
9 | process on Linux. It is OK however, when overcommit is enabled or is | |
10 | heuristic. However, when overcommit is restricted to a percentage of | |
11 | memory setting the contents of /proc/sys/vm/overcommit_memory as 2, it | |
12 | makes a difference since memory requests will fail. Hence, we do what | |
13 | we do with secure exec binaries, which is to call mmap on the region | |
14 | to be dropped with MAP_FIXED. This internally unmaps the pages in | |
15 | question and reduces the amount of memory accounted against the | |
16 | process. | |
17 | ||
18 | diff --git a/malloc/arena.c b/malloc/arena.c | |
19 | index f24e76c..b209e3b 100644 | |
20 | --- a/malloc/arena.c | |
21 | +++ b/malloc/arena.c | |
22 | @@ -19,6 +19,9 @@ | |
23 | ||
24 | #include <stdbool.h> | |
25 | ||
26 | +/* Get the implementation for check_may_shrink_heap. */ | |
27 | +#include <malloc-sysdep.h> | |
28 | + | |
29 | /* Compile-time constants. */ | |
30 | ||
31 | #define HEAP_MIN_SIZE (32*1024) | |
32 | @@ -621,10 +624,10 @@ shrink_heap(heap_info *h, long diff) | |
33 | new_size = (long)h->size - diff; | |
34 | if(new_size < (long)sizeof(*h)) | |
35 | return -1; | |
36 | - /* Try to re-map the extra heap space freshly to save memory, and | |
37 | - make it inaccessible. */ | |
38 | #ifdef _LIBC | |
39 | - if (__builtin_expect (__libc_enable_secure, 0)) | |
40 | + /* Try to re-map the extra heap space freshly to save memory, and make it | |
41 | + inaccessible. See malloc-sysdep.h to know when this is true. */ | |
42 | + if (__builtin_expect (check_may_shrink_heap (), 0)) | |
43 | #else | |
44 | if (1) | |
45 | #endif | |
46 | diff --git a/sysdeps/generic/malloc-sysdep.h b/sysdeps/generic/malloc-sysdep.h | |
47 | new file mode 100644 | |
48 | index 0000000..bbc48c0 | |
49 | --- /dev/null | |
50 | +++ b/sysdeps/generic/malloc-sysdep.h | |
51 | @@ -0,0 +1,25 @@ | |
52 | +/* System-specific malloc support functions. Generic version. | |
53 | + Copyright (C) 2012 Free Software Foundation, Inc. | |
54 | + This file is part of the GNU C Library. | |
55 | + | |
56 | + The GNU C Library is free software; you can redistribute it and/or | |
57 | + modify it under the terms of the GNU Lesser General Public | |
58 | + License as published by the Free Software Foundation; either | |
59 | + version 2.1 of the License, or (at your option) any later version. | |
60 | + | |
61 | + The GNU C Library is distributed in the hope that it will be useful, | |
62 | + but WITHOUT ANY WARRANTY; without even the implied warranty of | |
63 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
64 | + Lesser General Public License for more details. | |
65 | + | |
66 | + You should have received a copy of the GNU Lesser General Public | |
67 | + License along with the GNU C Library; if not, see | |
68 | + <http://www.gnu.org/licenses/>. */ | |
69 | + | |
70 | +/* Force an unmap when the heap shrinks in a secure exec. This ensures that | |
71 | + the old data pages immediately cease to be accessible. */ | |
72 | +static inline bool | |
73 | +check_may_shrink_heap (void) | |
74 | +{ | |
75 | + return __libc_enable_secure; | |
76 | +} | |
77 | diff --git a/sysdeps/unix/sysv/linux/malloc-sysdep.h b/sysdeps/unix/sysv/linux/malloc-sysdep.h | |
78 | new file mode 100644 | |
79 | index 0000000..f926aea | |
80 | --- /dev/null | |
81 | +++ b/sysdeps/unix/sysv/linux/malloc-sysdep.h | |
82 | @@ -0,0 +1,57 @@ | |
83 | +/* System-specific malloc support functions. Linux version. | |
84 | + Copyright (C) 2012 Free Software Foundation, Inc. | |
85 | + This file is part of the GNU C Library. | |
86 | + | |
87 | + The GNU C Library is free software; you can redistribute it and/or | |
88 | + modify it under the terms of the GNU Lesser General Public | |
89 | + License as published by the Free Software Foundation; either | |
90 | + version 2.1 of the License, or (at your option) any later version. | |
91 | + | |
92 | + The GNU C Library is distributed in the hope that it will be useful, | |
93 | + but WITHOUT ANY WARRANTY; without even the implied warranty of | |
94 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
95 | + Lesser General Public License for more details. | |
96 | + | |
97 | + You should have received a copy of the GNU Lesser General Public | |
98 | + License along with the GNU C Library; if not, see | |
99 | + <http://www.gnu.org/licenses/>. */ | |
100 | + | |
101 | +#include <fcntl.h> | |
102 | +#include <not-cancel.h> | |
103 | + | |
104 | +/* The Linux kernel overcommits address space by default and if there is not | |
105 | + enough memory available, it uses various parameters to decide the process to | |
106 | + kill. It is however possible to disable or curb this overcommit behavior | |
107 | + by setting the proc sysctl vm.overcommit_memory to the value '2' and with | |
108 | + that, a process is only allowed to use the maximum of a pre-determined | |
109 | + fraction of the total address space. In such a case, we want to make sure | |
110 | + that we are judicious with our heap usage as well, and explicitly give away | |
111 | + the freed top of the heap to reduce our commit charge. See the proc(5) man | |
112 | + page to know more about overcommit behavior. | |
113 | + | |
114 | + Other than that, we also force an unmap in a secure exec. */ | |
115 | +static inline bool | |
116 | +check_may_shrink_heap (void) | |
117 | +{ | |
118 | + static int may_shrink_heap = -1; | |
119 | + | |
120 | + if (__builtin_expect (may_shrink_heap >= 0, 1)) | |
121 | + return may_shrink_heap; | |
122 | + | |
123 | + may_shrink_heap = __libc_enable_secure; | |
124 | + | |
125 | + if (__builtin_expect (may_shrink_heap == 0, 1)) | |
126 | + { | |
127 | + int fd = open_not_cancel_2 ("/proc/sys/vm/overcommit_memory", | |
128 | + O_RDONLY | O_CLOEXEC); | |
129 | + if (fd >= 0) | |
130 | + { | |
131 | + char val; | |
132 | + ssize_t n = read_not_cancel (fd, &val, 1); | |
133 | + may_shrink_heap = n > 0 && val == '2'; | |
134 | + close_not_cancel_no_status (fd); | |
135 | + } | |
136 | + } | |
137 | + | |
138 | + return may_shrink_heap; | |
139 | +} |