2 * sgen-cardtable.c: Card table implementation for sgen
5 * Rodrigo Kumpera (rkumpera@novell.com)
7 * SGen is licensed under the terms of the MIT X11 license
9 * Copyright 2001-2003 Ximian, Inc
10 * Copyright 2003-2010 Novell, Inc.
11 * Copyright 2011 Xamarin Inc (http://www.xamarin.com)
13 * Permission is hereby granted, free of charge, to any person obtaining
14 * a copy of this software and associated documentation files (the
15 * "Software"), to deal in the Software without restriction, including
16 * without limitation the rights to use, copy, modify, merge, publish,
17 * distribute, sublicense, and/or sell copies of the Software, and to
18 * permit persons to whom the Software is furnished to do so, subject to
19 * the following conditions:
21 * The above copyright notice and this permission notice shall be
22 * included in all copies or substantial portions of the Software.
24 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
28 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
29 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
30 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
36 #include "metadata/sgen-gc.h"
37 #include "metadata/sgen-memory-governor.h"
38 #include "metadata/mono-gc.h"
40 #include "utils/mono-counters.h"
41 #include "utils/mono-mmap.h"
42 #include "utils/mono-logger-internal.h"
44 #define MIN_MINOR_COLLECTION_ALLOWANCE ((mword)(DEFAULT_NURSERY_SIZE * default_allowance_nursery_size_ratio))
46 /*Heap limits and allocation knobs*/
47 static mword max_heap_size = ((mword)0)- ((mword)1);
48 static mword soft_heap_limit = ((mword)0) - ((mword)1);
50 static double default_allowance_nursery_size_ratio = SGEN_DEFAULT_ALLOWANCE_NURSERY_SIZE_RATIO;
51 static double save_target_ratio = SGEN_DEFAULT_SAVE_TARGET_RATIO;
54 static mword allocated_heap;
55 static mword total_alloc = 0;
59 static gboolean debug_print_allowance = FALSE;
62 /* use this to tune when to do a major/minor collection */
63 static mword memory_pressure = 0;
64 static mword minor_collection_allowance;
65 static int minor_collection_sections_alloced = 0;
67 static int last_major_num_sections = 0;
68 static int last_los_memory_usage = 0;
69 static gboolean major_collection_happened = FALSE;
71 static gboolean need_calculate_minor_collection_allowance;
73 static int last_collection_old_num_major_sections;
74 static mword last_collection_los_memory_usage = 0;
75 static mword last_collection_old_los_memory_usage;
76 static mword last_collection_los_memory_alloced;
78 static mword sgen_memgov_available_free_space (void);
81 /* GC trigger heuristics. */
84 sgen_memgov_try_calculate_minor_collection_allowance (gboolean overwrite)
86 int num_major_sections, num_major_sections_saved;
87 mword los_memory_saved, new_major, new_heap_size, save_target, allowance_target;
90 g_assert (need_calculate_minor_collection_allowance);
92 if (!need_calculate_minor_collection_allowance)
95 if (!*major_collector.have_swept) {
97 minor_collection_allowance = MIN_MINOR_COLLECTION_ALLOWANCE;
101 num_major_sections = major_collector.get_num_major_sections ();
103 num_major_sections_saved = MAX (last_collection_old_num_major_sections - num_major_sections, 0);
104 los_memory_saved = MAX (last_collection_old_los_memory_usage - last_collection_los_memory_usage, 1);
106 new_major = num_major_sections * major_collector.section_size;
107 new_heap_size = new_major + last_collection_los_memory_usage;
109 save_target = (mword)((new_major + last_collection_los_memory_usage) * SGEN_DEFAULT_SAVE_TARGET_RATIO);
112 * We aim to allow the allocation of as many sections as is
113 * necessary to reclaim save_target sections in the next
114 * collection. We assume the collection pattern won't change.
115 * In the last cycle, we had num_major_sections_saved for
116 * minor_collection_sections_alloced. Assuming things won't
117 * change, this must be the same ratio as save_target for
118 * allowance_target, i.e.
120 * num_major_sections_saved save_target
121 * --------------------------------- == ----------------
122 * minor_collection_sections_alloced allowance_target
126 allowance_target = (mword)((double)save_target * (double)(minor_collection_sections_alloced * major_collector.section_size + last_collection_los_memory_alloced) / (double)(num_major_sections_saved * major_collector.section_size + los_memory_saved));
128 minor_collection_allowance = MAX (MIN (allowance_target, num_major_sections * major_collector.section_size + los_memory_usage), MIN_MINOR_COLLECTION_ALLOWANCE);
130 if (new_heap_size + minor_collection_allowance > soft_heap_limit) {
131 if (new_heap_size > soft_heap_limit)
132 minor_collection_allowance = MIN_MINOR_COLLECTION_ALLOWANCE;
134 minor_collection_allowance = MAX (soft_heap_limit - new_heap_size, MIN_MINOR_COLLECTION_ALLOWANCE);
137 if (debug_print_allowance) {
138 mword old_major = last_collection_old_num_major_sections * major_collector.section_size;
140 fprintf (gc_debug_file, "Before collection: %td bytes (%td major, %td LOS)\n",
141 old_major + last_collection_old_los_memory_usage, old_major, last_collection_old_los_memory_usage);
142 fprintf (gc_debug_file, "After collection: %td bytes (%td major, %td LOS)\n",
143 new_heap_size, new_major, last_collection_los_memory_usage);
144 fprintf (gc_debug_file, "Allowance: %td bytes\n", minor_collection_allowance);
147 if (major_collector.have_computed_minor_collection_allowance)
148 major_collector.have_computed_minor_collection_allowance ();
150 need_calculate_minor_collection_allowance = FALSE;
155 sgen_need_major_collection (mword space_needed)
157 mword los_alloced = los_memory_usage - MIN (last_collection_los_memory_usage, los_memory_usage);
158 return (space_needed > sgen_memgov_available_free_space ()) ||
159 minor_collection_sections_alloced * major_collector.section_size + los_alloced > minor_collection_allowance;
163 sgen_memgov_minor_collection_start (void)
165 sgen_memgov_try_calculate_minor_collection_allowance (FALSE);
169 sgen_memgov_minor_collection_end (void)
174 sgen_memgov_major_collection_start (void)
176 last_collection_old_num_major_sections = sgen_get_major_collector ()->get_num_major_sections ();
179 * A domain could have been freed, resulting in
180 * los_memory_usage being less than last_collection_los_memory_usage.
182 last_collection_los_memory_alloced = los_memory_usage - MIN (last_collection_los_memory_usage, los_memory_usage);
183 last_collection_old_los_memory_usage = los_memory_usage;
185 need_calculate_minor_collection_allowance = TRUE;
186 major_collection_happened = TRUE;
190 sgen_memgov_major_collection_end (void)
192 sgen_memgov_try_calculate_minor_collection_allowance (TRUE);
194 minor_collection_sections_alloced = 0;
195 last_collection_los_memory_usage = los_memory_usage;
199 sgen_memgov_collection_start (int generation)
201 last_major_num_sections = major_collector.get_num_major_sections ();
202 last_los_memory_usage = los_memory_usage;
203 major_collection_happened = FALSE;
207 sgen_memgov_collection_end (int generation, unsigned long pause_time, unsigned long bridge_pause_time)
209 int num_major_sections = major_collector.get_num_major_sections ();
211 if (major_collection_happened)
212 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_GC, "GC_MAJOR: %s pause %.2fms, bridge %.2fms major %dK/%dK los %dK/%dK",
213 generation ? "" : "(minor overflow)",
214 (int)pause_time / 1000.0f, (int)bridge_pause_time / 1000.0f,
215 major_collector.section_size * num_major_sections / 1024,
216 major_collector.section_size * last_major_num_sections / 1024,
217 los_memory_usage / 1024,
218 last_los_memory_usage / 1024);
220 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_GC, "GC_MINOR: pause %.2fms, bridge %.2fms promoted %dK major %dK los %dK",
221 (int)pause_time / 1000.0f, (int)bridge_pause_time / 1000.0f,
222 (num_major_sections - last_major_num_sections) * major_collector.section_size / 1024,
223 major_collector.section_size * num_major_sections / 1024,
224 los_memory_usage / 1024);
227 sgen_register_major_sections_alloced (int num_sections)
229 minor_collection_sections_alloced += num_sections;
233 sgen_get_minor_collection_allowance (void)
235 return minor_collection_allowance;
238 /* Memory pressure API */
240 /* Negative value to remove */
242 mono_gc_add_memory_pressure (gint64 value)
244 /* FIXME: Use interlocked functions */
246 memory_pressure += value;
252 Global GC memory tracking.
253 This tracks the total usage of memory by the GC. This includes
254 managed and unmanaged memory.
258 prot_flags_for_activate (int activate)
260 unsigned long prot_flags = activate? MONO_MMAP_READ|MONO_MMAP_WRITE: MONO_MMAP_NONE;
261 return prot_flags | MONO_MMAP_PRIVATE | MONO_MMAP_ANON;
265 * Allocate a big chunk of memory from the OS (usually 64KB to several megabytes).
266 * This must not require any lock.
269 sgen_alloc_os_memory (size_t size, int activate)
271 void *ptr = mono_valloc (0, size, prot_flags_for_activate (activate));
273 SGEN_ATOMIC_ADD_P (total_alloc, size);
277 /* size must be a power of 2 */
279 sgen_alloc_os_memory_aligned (size_t size, mword alignment, gboolean activate)
281 void *ptr = mono_valloc_aligned (size, alignment, prot_flags_for_activate (activate));
283 SGEN_ATOMIC_ADD_P (total_alloc, size);
288 * Free the memory returned by sgen_alloc_os_memory (), returning it to the OS.
291 sgen_free_os_memory (void *addr, size_t size)
293 mono_vfree (addr, size);
294 SGEN_ATOMIC_ADD_P (total_alloc, -size);
298 mono_gc_get_heap_size (void)
306 This limit the max size of the heap. It takes into account
307 only memory actively in use to hold heap objects and not
308 for other parts of the GC.
311 sgen_memgov_available_free_space (void)
313 return max_heap_size - MIN (allocated_heap, max_heap_size);
317 sgen_memgov_release_space (mword size, int space)
319 SGEN_ATOMIC_ADD_P (allocated_heap, -size);
323 sgen_memgov_try_alloc_space (mword size, int space)
325 if (sgen_memgov_available_free_space () < size)
328 SGEN_ATOMIC_ADD_P (allocated_heap, size);
329 mono_runtime_resource_check_limit (MONO_RESOURCE_GC_HEAP, allocated_heap);
334 sgen_memgov_init (glong max_heap, glong soft_limit, gboolean debug_allowance, double allowance_ratio, double save_target)
337 soft_heap_limit = soft_limit;
339 debug_print_allowance = debug_allowance;
344 if (max_heap < soft_limit) {
345 fprintf (stderr, "max-heap-size must be at least as large as soft-heap-limit.\n");
349 if (max_heap < sgen_nursery_size * 4) {
350 fprintf (stderr, "max-heap-size must be at least 4 times larger than nursery size.\n");
353 max_heap_size = max_heap - sgen_nursery_size;
355 minor_collection_allowance = MIN_MINOR_COLLECTION_ALLOWANCE;
358 default_allowance_nursery_size_ratio = allowance_ratio;
361 save_target_ratio = save_target;