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 34 size_t MinNewSize = 0; 35 36 size_t MinOldSize = 0; 37 size_t MaxOldSize = 0; 38 39 size_t GenAlignment = 0; 40 41 size_t GenArguments::conservative_max_heap_alignment() { return (size_t)Generation::GenGrain; } 42 43 static 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 48 static size_t old_gen_size_lower_bound() { 49 return align_up(SpaceAlignment, GenAlignment); 50 } 51 52 size_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 56 static 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 63 void GenArguments::initialize_alignments() { 64 SpaceAlignment = GenAlignment = (size_t)Generation::GenGrain; 65 HeapAlignment = compute_heap_alignment(); 66 } 67 68 void 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 DEBUG_ONLY(assert_flags();) 200 } 201 202 // Values set on the command line win over any ergonomically 203 // set command line parameters. 204 // Ergonomic choice of parameters are done before this 205 // method is called. Values for command line parameters such as NewSize 206 // and MaxNewSize feed those ergonomic choices into this method. 207 // This method makes the final generation sizings consistent with 208 // themselves and with overall heap sizings. 209 // In the absence of explicitly set command line flags, policies 210 // such as the use of NewRatio are used to size the generation. 211 212 // Minimum sizes of the generations may be different than 213 // the initial sizes. An inconsistency is permitted here 214 // in the total size that can be specified explicitly by 215 // command line specification of OldSize and NewSize and 216 // also a command line specification of -Xms. Issue a warning 217 // but allow the values to pass. 218 void GenArguments::initialize_size_info() { 219 GCArguments::initialize_size_info(); 220 221 size_t max_young_size = MaxNewSize; 222 223 // Determine maximum size of the young generation. 224 225 if (FLAG_IS_DEFAULT(MaxNewSize)) { 226 max_young_size = scale_by_NewRatio_aligned(MaxHeapSize, GenAlignment); 227 // Bound the maximum size by NewSize below (since it historically 228 // would have been NewSize and because the NewRatio calculation could 229 // yield a size that is too small) and bound it by MaxNewSize above. 230 // Ergonomics plays here by previously calculating the desired 231 // NewSize and MaxNewSize. 232 max_young_size = clamp(max_young_size, NewSize, MaxNewSize); 233 } 234 235 // Given the maximum young size, determine the initial and 236 // minimum young sizes. 237 size_t initial_young_size = NewSize; 238 239 if (MaxHeapSize == InitialHeapSize) { 240 // The maximum and initial heap sizes are the same so the generation's 241 // initial size must be the same as it maximum size. Use NewSize as the 242 // size if set on command line. 243 max_young_size = FLAG_IS_CMDLINE(NewSize) ? NewSize : max_young_size; 244 initial_young_size = max_young_size; 245 246 // Also update the minimum size if min == initial == max. 247 if (MaxHeapSize == MinHeapSize) { 248 MinNewSize = max_young_size; 249 } 250 } else { 251 if (FLAG_IS_CMDLINE(NewSize)) { 252 // If NewSize is set on the command line, we should use it as 253 // the initial size, but make sure it is within the heap bounds. 254 initial_young_size = 255 MIN2(max_young_size, bound_minus_alignment(NewSize, InitialHeapSize, GenAlignment)); 256 MinNewSize = bound_minus_alignment(initial_young_size, MinHeapSize, GenAlignment); 257 } else { 258 // For the case where NewSize is not set on the command line, use 259 // NewRatio to size the initial generation size. Use the current 260 // NewSize as the floor, because if NewRatio is overly large, the resulting 261 // size can be too small. 262 initial_young_size = 263 clamp(scale_by_NewRatio_aligned(InitialHeapSize, GenAlignment), NewSize, max_young_size); 264 } 265 } 266 267 log_trace(gc, heap)("1: Minimum young " SIZE_FORMAT " Initial young " SIZE_FORMAT " Maximum young " SIZE_FORMAT, 268 MinNewSize, initial_young_size, max_young_size); 269 270 // At this point the minimum, initial and maximum sizes 271 // of the overall heap and of the young generation have been determined. 272 // The maximum old size can be determined from the maximum young 273 // and maximum heap size since no explicit flags exist 274 // for setting the old generation maximum. 275 MaxOldSize = MAX2(MaxHeapSize - max_young_size, GenAlignment); 276 277 size_t initial_old_size = OldSize; 278 279 // If no explicit command line flag has been set for the 280 // old generation size, use what is left. 281 if (!FLAG_IS_CMDLINE(OldSize)) { 282 // The user has not specified any value but the ergonomics 283 // may have chosen a value (which may or may not be consistent 284 // with the overall heap size). In either case make 285 // the minimum, maximum and initial sizes consistent 286 // with the young sizes and the overall heap sizes. 287 MinOldSize = GenAlignment; 288 initial_old_size = clamp(InitialHeapSize - initial_young_size, MinOldSize, MaxOldSize); 289 // MaxOldSize has already been made consistent above. 290 } else { 291 // OldSize has been explicitly set on the command line. Use it 292 // for the initial size but make sure the minimum allow a young 293 // generation to fit as well. 294 // If the user has explicitly set an OldSize that is inconsistent 295 // with other command line flags, issue a warning. 296 // The generation minimums and the overall heap minimum should 297 // be within one generation alignment. 298 if (initial_old_size > MaxOldSize) { 299 log_warning(gc, ergo)("Inconsistency between maximum heap size and maximum " 300 "generation sizes: using maximum heap = " SIZE_FORMAT 301 ", -XX:OldSize flag is being ignored", 302 MaxHeapSize); 303 initial_old_size = MaxOldSize; 304 } 305 306 MinOldSize = MIN2(initial_old_size, MinHeapSize - MinNewSize); 307 } 308 309 // The initial generation sizes should match the initial heap size, 310 // if not issue a warning and resize the generations. This behavior 311 // differs from JDK8 where the generation sizes have higher priority 312 // than the initial heap size. 313 if ((initial_old_size + initial_young_size) != InitialHeapSize) { 314 log_warning(gc, ergo)("Inconsistency between generation sizes and heap size, resizing " 315 "the generations to fit the heap."); 316 317 size_t desired_young_size = InitialHeapSize - initial_old_size; 318 if (InitialHeapSize < initial_old_size) { 319 // Old want all memory, use minimum for young and rest for old 320 initial_young_size = MinNewSize; 321 initial_old_size = InitialHeapSize - MinNewSize; 322 } else if (desired_young_size > max_young_size) { 323 // Need to increase both young and old generation 324 initial_young_size = max_young_size; 325 initial_old_size = InitialHeapSize - max_young_size; 326 } else if (desired_young_size < MinNewSize) { 327 // Need to decrease both young and old generation 328 initial_young_size = MinNewSize; 329 initial_old_size = InitialHeapSize - MinNewSize; 330 } else { 331 // The young generation boundaries allow us to only update the 332 // young generation. 333 initial_young_size = desired_young_size; 334 } 335 336 log_trace(gc, heap)("2: Minimum young " SIZE_FORMAT " Initial young " SIZE_FORMAT " Maximum young " SIZE_FORMAT, 337 MinNewSize, initial_young_size, max_young_size); 338 } 339 340 // Write back to flags if necessary. 341 if (NewSize != initial_young_size) { 342 FLAG_SET_ERGO(NewSize, initial_young_size); 343 } 344 345 if (MaxNewSize != max_young_size) { 346 FLAG_SET_ERGO(MaxNewSize, max_young_size); 347 } 348 349 if (OldSize != initial_old_size) { 350 FLAG_SET_ERGO(OldSize, initial_old_size); 351 } 352 353 log_trace(gc, heap)("Minimum old " SIZE_FORMAT " Initial old " SIZE_FORMAT " Maximum old " SIZE_FORMAT, 354 MinOldSize, OldSize, MaxOldSize); 355 356 DEBUG_ONLY(assert_size_info();) 357 } 358 359 #ifdef ASSERT 360 void GenArguments::assert_flags() { 361 GCArguments::assert_flags(); 362 assert(NewSize >= MinNewSize, "Ergonomics decided on a too small young gen size"); 363 assert(NewSize <= MaxNewSize, "Ergonomics decided on incompatible initial and maximum young gen sizes"); 364 assert(FLAG_IS_DEFAULT(MaxNewSize) || MaxNewSize < MaxHeapSize, "Ergonomics decided on incompatible maximum young gen and heap sizes"); 365 assert(NewSize % GenAlignment == 0, "NewSize alignment"); 366 assert(FLAG_IS_DEFAULT(MaxNewSize) || MaxNewSize % GenAlignment == 0, "MaxNewSize alignment"); 367 assert(OldSize + NewSize <= MaxHeapSize, "Ergonomics decided on incompatible generation and heap sizes"); 368 assert(OldSize % GenAlignment == 0, "OldSize alignment"); 369 } 370 371 void GenArguments::assert_size_info() { 372 GCArguments::assert_size_info(); 373 // GenArguments::initialize_size_info may update the MaxNewSize 374 assert(MaxNewSize < MaxHeapSize, "Ergonomics decided on incompatible maximum young and heap sizes"); 375 assert(MinNewSize <= NewSize, "Ergonomics decided on incompatible minimum and initial young gen sizes"); 376 assert(NewSize <= MaxNewSize, "Ergonomics decided on incompatible initial and maximum young gen sizes"); 377 assert(MinNewSize % GenAlignment == 0, "_min_young_size alignment"); 378 assert(NewSize % GenAlignment == 0, "_initial_young_size alignment"); 379 assert(MaxNewSize % GenAlignment == 0, "MaxNewSize alignment"); 380 assert(MinNewSize <= bound_minus_alignment(MinNewSize, MinHeapSize, GenAlignment), 381 "Ergonomics made minimum young generation larger than minimum heap"); 382 assert(NewSize <= bound_minus_alignment(NewSize, InitialHeapSize, GenAlignment), 383 "Ergonomics made initial young generation larger than initial heap"); 384 assert(MaxNewSize <= bound_minus_alignment(MaxNewSize, MaxHeapSize, GenAlignment), 385 "Ergonomics made maximum young generation lager than maximum heap"); 386 assert(MinOldSize <= OldSize, "Ergonomics decided on incompatible minimum and initial old gen sizes"); 387 assert(OldSize <= MaxOldSize, "Ergonomics decided on incompatible initial and maximum old gen sizes"); 388 assert(MaxOldSize % GenAlignment == 0, "MaxOldSize alignment"); 389 assert(OldSize % GenAlignment == 0, "OldSize alignment"); 390 assert(MaxHeapSize <= (MaxNewSize + MaxOldSize), "Total maximum heap sizes must be sum of generation maximum sizes"); 391 assert(MinNewSize + MinOldSize <= MinHeapSize, "Minimum generation sizes exceed minimum heap size"); 392 assert(NewSize + OldSize == InitialHeapSize, "Initial generation sizes should match initial heap size"); 393 assert(MaxNewSize + MaxOldSize == MaxHeapSize, "Maximum generation sizes should match maximum heap size"); 394 } 395 #endif // ASSERT