1/*
2 * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 *
23 */
24
25#include "precompiled.hpp"
26#include "gc/shared/genArguments.hpp"
27#include "gc/shared/generation.hpp"
28#include "logging/log.hpp"
29#include "runtime/globals_extension.hpp"
30#include "runtime/java.hpp"
31#include "utilities/align.hpp"
32#include "utilities/globalDefinitions.hpp"
33
34size_t MinNewSize = 0;
35
36size_t MinOldSize = 0;
37size_t MaxOldSize = 0;
38
39size_t GenAlignment = 0;
40
41size_t GenArguments::conservative_max_heap_alignment() { return (size_t)Generation::GenGrain; }
42
43static size_t young_gen_size_lower_bound() {
44 // The young generation must be aligned and have room for eden + two survivors
45 return align_up(3 * SpaceAlignment, GenAlignment);
46}
47
48static size_t old_gen_size_lower_bound() {
49 return align_up(SpaceAlignment, GenAlignment);
50}
51
52size_t GenArguments::scale_by_NewRatio_aligned(size_t base_size, size_t alignment) {
53 return align_down_bounded(base_size / (NewRatio + 1), alignment);
54}
55
56static size_t bound_minus_alignment(size_t desired_size,
57 size_t maximum_size,
58 size_t alignment) {
59 size_t max_minus = maximum_size - alignment;
60 return desired_size < max_minus ? desired_size : max_minus;
61}
62
63void GenArguments::initialize_alignments() {
64 SpaceAlignment = GenAlignment = (size_t)Generation::GenGrain;
65 HeapAlignment = compute_heap_alignment();
66}
67
68void GenArguments::initialize_heap_flags_and_sizes() {
69 GCArguments::initialize_heap_flags_and_sizes();
70
71 assert(GenAlignment != 0, "Generation alignment not set up properly");
72 assert(HeapAlignment >= GenAlignment,
73 "HeapAlignment: " SIZE_FORMAT " less than GenAlignment: " SIZE_FORMAT,
74 HeapAlignment, GenAlignment);
75 assert(GenAlignment % SpaceAlignment == 0,
76 "GenAlignment: " SIZE_FORMAT " not aligned by SpaceAlignment: " SIZE_FORMAT,
77 GenAlignment, SpaceAlignment);
78 assert(HeapAlignment % GenAlignment == 0,
79 "HeapAlignment: " SIZE_FORMAT " not aligned by GenAlignment: " SIZE_FORMAT,
80 HeapAlignment, GenAlignment);
81
82 // All generational heaps have a young gen; handle those flags here
83
84 // Make sure the heap is large enough for two generations
85 size_t smallest_new_size = young_gen_size_lower_bound();
86 size_t smallest_heap_size = align_up(smallest_new_size + old_gen_size_lower_bound(),
87 HeapAlignment);
88 if (MaxHeapSize < smallest_heap_size) {
89 FLAG_SET_ERGO(MaxHeapSize, smallest_heap_size);
90 }
91 // If needed, synchronize MinHeapSize size and InitialHeapSize
92 if (MinHeapSize < smallest_heap_size) {
93 FLAG_SET_ERGO(MinHeapSize, smallest_heap_size);
94 if (InitialHeapSize < MinHeapSize) {
95 FLAG_SET_ERGO(InitialHeapSize, smallest_heap_size);
96 }
97 }
98
99 // Make sure NewSize allows an old generation to fit even if set on the command line
100 if (FLAG_IS_CMDLINE(NewSize) && NewSize >= InitialHeapSize) {
101 log_warning(gc, ergo)("NewSize was set larger than initial heap size, will use initial heap size.");
102 FLAG_SET_ERGO(NewSize, bound_minus_alignment(NewSize, InitialHeapSize, GenAlignment));
103 }
104
105 // Now take the actual NewSize into account. We will silently increase NewSize
106 // if the user specified a smaller or unaligned value.
107 size_t bounded_new_size = bound_minus_alignment(NewSize, MaxHeapSize, GenAlignment);
108 bounded_new_size = MAX2(smallest_new_size, align_down(bounded_new_size, GenAlignment));
109 if (bounded_new_size != NewSize) {
110 FLAG_SET_ERGO(NewSize, bounded_new_size);
111 }
112 MinNewSize = smallest_new_size;
113
114 if (!FLAG_IS_DEFAULT(MaxNewSize)) {
115 if (MaxNewSize >= MaxHeapSize) {
116 // Make sure there is room for an old generation
117 size_t smaller_max_new_size = MaxHeapSize - GenAlignment;
118 if (FLAG_IS_CMDLINE(MaxNewSize)) {
119 log_warning(gc, ergo)("MaxNewSize (" SIZE_FORMAT "k) is equal to or greater than the entire "
120 "heap (" SIZE_FORMAT "k). A new max generation size of " SIZE_FORMAT "k will be used.",
121 MaxNewSize/K, MaxHeapSize/K, smaller_max_new_size/K);
122 }
123 FLAG_SET_ERGO(MaxNewSize, smaller_max_new_size);
124 if (NewSize > MaxNewSize) {
125 FLAG_SET_ERGO(NewSize, MaxNewSize);
126 }
127 } else if (MaxNewSize < NewSize) {
128 FLAG_SET_ERGO(MaxNewSize, NewSize);
129 } else if (!is_aligned(MaxNewSize, GenAlignment)) {
130 FLAG_SET_ERGO(MaxNewSize, align_down(MaxNewSize, GenAlignment));
131 }
132 }
133
134 if (NewSize > MaxNewSize) {
135 // At this point this should only happen if the user specifies a large NewSize and/or
136 // a small (but not too small) MaxNewSize.
137 if (FLAG_IS_CMDLINE(MaxNewSize)) {
138 log_warning(gc, ergo)("NewSize (" SIZE_FORMAT "k) is greater than the MaxNewSize (" SIZE_FORMAT "k). "
139 "A new max generation size of " SIZE_FORMAT "k will be used.",
140 NewSize/K, MaxNewSize/K, NewSize/K);
141 }
142 FLAG_SET_ERGO(MaxNewSize, NewSize);
143 }
144
145 if (SurvivorRatio < 1 || NewRatio < 1) {
146 vm_exit_during_initialization("Invalid young gen ratio specified");
147 }
148
149 if (OldSize < old_gen_size_lower_bound()) {
150 FLAG_SET_ERGO(OldSize, old_gen_size_lower_bound());
151 }
152 if (!is_aligned(OldSize, GenAlignment)) {
153 FLAG_SET_ERGO(OldSize, align_down(OldSize, GenAlignment));
154 }
155
156 if (FLAG_IS_CMDLINE(OldSize) && FLAG_IS_DEFAULT(MaxHeapSize)) {
157 // NewRatio will be used later to set the young generation size so we use
158 // it to calculate how big the heap should be based on the requested OldSize
159 // and NewRatio.
160 assert(NewRatio > 0, "NewRatio should have been set up earlier");
161 size_t calculated_heapsize = (OldSize / NewRatio) * (NewRatio + 1);
162
163 calculated_heapsize = align_up(calculated_heapsize, HeapAlignment);
164 FLAG_SET_ERGO(MaxHeapSize, calculated_heapsize);
165 FLAG_SET_ERGO(InitialHeapSize, calculated_heapsize);
166 }
167
168 // Adjust NewSize and OldSize or MaxHeapSize to match each other
169 if (NewSize + OldSize > MaxHeapSize) {
170 if (FLAG_IS_CMDLINE(MaxHeapSize)) {
171 // Somebody has set a maximum heap size with the intention that we should not
172 // exceed it. Adjust New/OldSize as necessary.
173 size_t calculated_size = NewSize + OldSize;
174 double shrink_factor = (double) MaxHeapSize / calculated_size;
175 size_t smaller_new_size = align_down((size_t)(NewSize * shrink_factor), GenAlignment);
176 FLAG_SET_ERGO(NewSize, MAX2(young_gen_size_lower_bound(), smaller_new_size));
177
178 // OldSize is already aligned because above we aligned MaxHeapSize to
179 // HeapAlignment, and we just made sure that NewSize is aligned to
180 // GenAlignment. In initialize_flags() we verified that HeapAlignment
181 // is a multiple of GenAlignment.
182 FLAG_SET_ERGO(OldSize, MaxHeapSize - NewSize);
183 } else {
184 FLAG_SET_ERGO(MaxHeapSize, align_up(NewSize + OldSize, HeapAlignment));
185 }
186 }
187
188 // Update NewSize, if possible, to avoid sizing the young gen too small when only
189 // OldSize is set on the command line.
190 if (FLAG_IS_CMDLINE(OldSize) && !FLAG_IS_CMDLINE(NewSize)) {
191 if (OldSize < InitialHeapSize) {
192 size_t new_size = InitialHeapSize - OldSize;
193 if (new_size >= MinNewSize && new_size <= MaxNewSize) {
194 FLAG_SET_ERGO(NewSize, new_size);
195 }
196 }
197 }
198
199 always_do_update_barrier = UseConcMarkSweepGC;
200
201 DEBUG_ONLY(assert_flags();)
202}
203
204// Values set on the command line win over any ergonomically
205// set command line parameters.
206// Ergonomic choice of parameters are done before this
207// method is called. Values for command line parameters such as NewSize
208// and MaxNewSize feed those ergonomic choices into this method.
209// This method makes the final generation sizings consistent with
210// themselves and with overall heap sizings.
211// In the absence of explicitly set command line flags, policies
212// such as the use of NewRatio are used to size the generation.
213
214// Minimum sizes of the generations may be different than
215// the initial sizes. An inconsistency is permitted here
216// in the total size that can be specified explicitly by
217// command line specification of OldSize and NewSize and
218// also a command line specification of -Xms. Issue a warning
219// but allow the values to pass.
220void GenArguments::initialize_size_info() {
221 GCArguments::initialize_size_info();
222
223 size_t max_young_size = MaxNewSize;
224
225 // Determine maximum size of the young generation.
226
227 if (FLAG_IS_DEFAULT(MaxNewSize)) {
228 max_young_size = scale_by_NewRatio_aligned(MaxHeapSize, GenAlignment);
229 // Bound the maximum size by NewSize below (since it historically
230 // would have been NewSize and because the NewRatio calculation could
231 // yield a size that is too small) and bound it by MaxNewSize above.
232 // Ergonomics plays here by previously calculating the desired
233 // NewSize and MaxNewSize.
234 max_young_size = MIN2(MAX2(max_young_size, NewSize), MaxNewSize);
235 }
236
237 // Given the maximum young size, determine the initial and
238 // minimum young sizes.
239 size_t initial_young_size = NewSize;
240
241 if (MaxHeapSize == InitialHeapSize) {
242 // The maximum and initial heap sizes are the same so the generation's
243 // initial size must be the same as it maximum size. Use NewSize as the
244 // size if set on command line.
245 max_young_size = FLAG_IS_CMDLINE(NewSize) ? NewSize : max_young_size;
246 initial_young_size = max_young_size;
247
248 // Also update the minimum size if min == initial == max.
249 if (MaxHeapSize == MinHeapSize) {
250 MinNewSize = max_young_size;
251 }
252 } else {
253 if (FLAG_IS_CMDLINE(NewSize)) {
254 // If NewSize is set on the command line, we should use it as
255 // the initial size, but make sure it is within the heap bounds.
256 initial_young_size =
257 MIN2(max_young_size, bound_minus_alignment(NewSize, InitialHeapSize, GenAlignment));
258 MinNewSize = bound_minus_alignment(initial_young_size, MinHeapSize, GenAlignment);
259 } else {
260 // For the case where NewSize is not set on the command line, use
261 // NewRatio to size the initial generation size. Use the current
262 // NewSize as the floor, because if NewRatio is overly large, the resulting
263 // size can be too small.
264 initial_young_size =
265 MIN2(max_young_size, MAX2(scale_by_NewRatio_aligned(InitialHeapSize, GenAlignment), NewSize));
266 }
267 }
268
269 log_trace(gc, heap)("1: Minimum young " SIZE_FORMAT " Initial young " SIZE_FORMAT " Maximum young " SIZE_FORMAT,
270 MinNewSize, initial_young_size, max_young_size);
271
272 // At this point the minimum, initial and maximum sizes
273 // of the overall heap and of the young generation have been determined.
274 // The maximum old size can be determined from the maximum young
275 // and maximum heap size since no explicit flags exist
276 // for setting the old generation maximum.
277 MaxOldSize = MAX2(MaxHeapSize - max_young_size, GenAlignment);
278
279 size_t initial_old_size = OldSize;
280
281 // If no explicit command line flag has been set for the
282 // old generation size, use what is left.
283 if (!FLAG_IS_CMDLINE(OldSize)) {
284 // The user has not specified any value but the ergonomics
285 // may have chosen a value (which may or may not be consistent
286 // with the overall heap size). In either case make
287 // the minimum, maximum and initial sizes consistent
288 // with the young sizes and the overall heap sizes.
289 MinOldSize = GenAlignment;
290 initial_old_size = MIN2(MaxOldSize, MAX2(InitialHeapSize - initial_young_size, MinOldSize));
291 // MaxOldSize has already been made consistent above.
292 } else {
293 // OldSize has been explicitly set on the command line. Use it
294 // for the initial size but make sure the minimum allow a young
295 // generation to fit as well.
296 // If the user has explicitly set an OldSize that is inconsistent
297 // with other command line flags, issue a warning.
298 // The generation minimums and the overall heap minimum should
299 // be within one generation alignment.
300 if (initial_old_size > MaxOldSize) {
301 log_warning(gc, ergo)("Inconsistency between maximum heap size and maximum "
302 "generation sizes: using maximum heap = " SIZE_FORMAT
303 ", -XX:OldSize flag is being ignored",
304 MaxHeapSize);
305 initial_old_size = MaxOldSize;
306 }
307
308 MinOldSize = MIN2(initial_old_size, MinHeapSize - MinNewSize);
309 }
310
311 // The initial generation sizes should match the initial heap size,
312 // if not issue a warning and resize the generations. This behavior
313 // differs from JDK8 where the generation sizes have higher priority
314 // than the initial heap size.
315 if ((initial_old_size + initial_young_size) != InitialHeapSize) {
316 log_warning(gc, ergo)("Inconsistency between generation sizes and heap size, resizing "
317 "the generations to fit the heap.");
318
319 size_t desired_young_size = InitialHeapSize - initial_old_size;
320 if (InitialHeapSize < initial_old_size) {
321 // Old want all memory, use minimum for young and rest for old
322 initial_young_size = MinNewSize;
323 initial_old_size = InitialHeapSize - MinNewSize;
324 } else if (desired_young_size > max_young_size) {
325 // Need to increase both young and old generation
326 initial_young_size = max_young_size;
327 initial_old_size = InitialHeapSize - max_young_size;
328 } else if (desired_young_size < MinNewSize) {
329 // Need to decrease both young and old generation
330 initial_young_size = MinNewSize;
331 initial_old_size = InitialHeapSize - MinNewSize;
332 } else {
333 // The young generation boundaries allow us to only update the
334 // young generation.
335 initial_young_size = desired_young_size;
336 }
337
338 log_trace(gc, heap)("2: Minimum young " SIZE_FORMAT " Initial young " SIZE_FORMAT " Maximum young " SIZE_FORMAT,
339 MinNewSize, initial_young_size, max_young_size);
340 }
341
342 // Write back to flags if necessary.
343 if (NewSize != initial_young_size) {
344 FLAG_SET_ERGO(NewSize, initial_young_size);
345 }
346
347 if (MaxNewSize != max_young_size) {
348 FLAG_SET_ERGO(MaxNewSize, max_young_size);
349 }
350
351 if (OldSize != initial_old_size) {
352 FLAG_SET_ERGO(OldSize, initial_old_size);
353 }
354
355 log_trace(gc, heap)("Minimum old " SIZE_FORMAT " Initial old " SIZE_FORMAT " Maximum old " SIZE_FORMAT,
356 MinOldSize, OldSize, MaxOldSize);
357
358 DEBUG_ONLY(assert_size_info();)
359}
360
361#ifdef ASSERT
362void GenArguments::assert_flags() {
363 GCArguments::assert_flags();
364 assert(NewSize >= MinNewSize, "Ergonomics decided on a too small young gen size");
365 assert(NewSize <= MaxNewSize, "Ergonomics decided on incompatible initial and maximum young gen sizes");
366 assert(FLAG_IS_DEFAULT(MaxNewSize) || MaxNewSize < MaxHeapSize, "Ergonomics decided on incompatible maximum young gen and heap sizes");
367 assert(NewSize % GenAlignment == 0, "NewSize alignment");
368 assert(FLAG_IS_DEFAULT(MaxNewSize) || MaxNewSize % GenAlignment == 0, "MaxNewSize alignment");
369 assert(OldSize + NewSize <= MaxHeapSize, "Ergonomics decided on incompatible generation and heap sizes");
370 assert(OldSize % GenAlignment == 0, "OldSize alignment");
371}
372
373void GenArguments::assert_size_info() {
374 GCArguments::assert_size_info();
375 // GenArguments::initialize_size_info may update the MaxNewSize
376 assert(MaxNewSize < MaxHeapSize, "Ergonomics decided on incompatible maximum young and heap sizes");
377 assert(MinNewSize <= NewSize, "Ergonomics decided on incompatible minimum and initial young gen sizes");
378 assert(NewSize <= MaxNewSize, "Ergonomics decided on incompatible initial and maximum young gen sizes");
379 assert(MinNewSize % GenAlignment == 0, "_min_young_size alignment");
380 assert(NewSize % GenAlignment == 0, "_initial_young_size alignment");
381 assert(MaxNewSize % GenAlignment == 0, "MaxNewSize alignment");
382 assert(MinNewSize <= bound_minus_alignment(MinNewSize, MinHeapSize, GenAlignment),
383 "Ergonomics made minimum young generation larger than minimum heap");
384 assert(NewSize <= bound_minus_alignment(NewSize, InitialHeapSize, GenAlignment),
385 "Ergonomics made initial young generation larger than initial heap");
386 assert(MaxNewSize <= bound_minus_alignment(MaxNewSize, MaxHeapSize, GenAlignment),
387 "Ergonomics made maximum young generation lager than maximum heap");
388 assert(MinOldSize <= OldSize, "Ergonomics decided on incompatible minimum and initial old gen sizes");
389 assert(OldSize <= MaxOldSize, "Ergonomics decided on incompatible initial and maximum old gen sizes");
390 assert(MaxOldSize % GenAlignment == 0, "MaxOldSize alignment");
391 assert(OldSize % GenAlignment == 0, "OldSize alignment");
392 assert(MaxHeapSize <= (MaxNewSize + MaxOldSize), "Total maximum heap sizes must be sum of generation maximum sizes");
393 assert(MinNewSize + MinOldSize <= MinHeapSize, "Minimum generation sizes exceed minimum heap size");
394 assert(NewSize + OldSize == InitialHeapSize, "Initial generation sizes should match initial heap size");
395 assert(MaxNewSize + MaxOldSize == MaxHeapSize, "Maximum generation sizes should match maximum heap size");
396}
397#endif // ASSERT
398