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/genSettings.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 static size_t young_gen_size_lower_bound(const GenSettings& s) { 35 // The young generation must be aligned and have room for eden + two survivors 36 return align_up(3 * s._space_alignment, s._gen_alignment); 37 } 38 39 static size_t old_gen_size_lower_bound(const GenSettings& s) { 40 return align_up(s._space_alignment, s._gen_alignment); 41 } 42 43 static size_t scale_by_NewRatio_aligned(size_t base_size, size_t alignment) { 44 return align_down_bounded(base_size / (NewRatio + 1), alignment); 45 } 46 47 static size_t bound_minus_alignment(size_t desired_size, 48 size_t maximum_size, 49 size_t alignment) { 50 size_t max_minus = maximum_size - alignment; 51 return desired_size < max_minus ? desired_size : max_minus; 52 } 53 54 void GenArguments::initialize_heap_flags(GenSettings& s) { 55 GCArguments::initialize_heap_flags(s); 56 57 assert(s._gen_alignment != 0, "Generation alignment not set up properly"); 58 assert(s._heap_alignment >= s._gen_alignment, 59 "heap_alignment: " SIZE_FORMAT " less than gen_alignment: " SIZE_FORMAT, 60 s._heap_alignment, s._gen_alignment); 61 assert(s._gen_alignment % s._space_alignment == 0, 62 "gen_alignment: " SIZE_FORMAT " not aligned by space_alignment: " SIZE_FORMAT, 63 s._gen_alignment, s._space_alignment); 64 assert(s._heap_alignment % s._gen_alignment == 0, 65 "heap_alignment: " SIZE_FORMAT " not aligned by gen_alignment: " SIZE_FORMAT, 66 s._heap_alignment, s._gen_alignment); 67 68 // All generational heaps have a young gen; handle those flags here 69 70 // Make sure the heap is large enough for two generations 71 size_t smallest_new_size = young_gen_size_lower_bound(s); 72 size_t smallest_heap_size = align_up(smallest_new_size + old_gen_size_lower_bound(s), 73 s._heap_alignment); 74 if (MaxHeapSize < smallest_heap_size) { 75 FLAG_SET_ERGO(size_t, MaxHeapSize, smallest_heap_size); 76 s._max_heap_byte_size = MaxHeapSize; 77 } 78 // If needed, synchronize _min_heap_byte size and _initial_heap_byte_size 79 if (s._min_heap_byte_size < smallest_heap_size) { 80 s._min_heap_byte_size = smallest_heap_size; 81 if (InitialHeapSize < s._min_heap_byte_size) { 82 FLAG_SET_ERGO(size_t, InitialHeapSize, smallest_heap_size); 83 s._initial_heap_byte_size = smallest_heap_size; 84 } 85 } 86 87 // Make sure NewSize allows an old generation to fit even if set on the command line 88 if (FLAG_IS_CMDLINE(NewSize) && NewSize >= s._initial_heap_byte_size) { 89 log_warning(gc, ergo)("NewSize was set larger than initial heap size, will use initial heap size."); 90 FLAG_SET_ERGO(size_t, NewSize, bound_minus_alignment(NewSize, s._initial_heap_byte_size, s._gen_alignment)); 91 } 92 93 // Now take the actual NewSize into account. We will silently increase NewSize 94 // if the user specified a smaller or unaligned value. 95 size_t bounded_new_size = bound_minus_alignment(NewSize, MaxHeapSize, s._gen_alignment); 96 bounded_new_size = MAX2(smallest_new_size, align_down(bounded_new_size, s._gen_alignment)); 97 if (bounded_new_size != NewSize) { 98 FLAG_SET_ERGO(size_t, NewSize, bounded_new_size); 99 } 100 s._min_young_size = smallest_new_size; 101 s._initial_young_size = NewSize; 102 103 if (!FLAG_IS_DEFAULT(MaxNewSize)) { 104 if (MaxNewSize >= MaxHeapSize) { 105 // Make sure there is room for an old generation 106 size_t smaller_max_new_size = MaxHeapSize - s._gen_alignment; 107 if (FLAG_IS_CMDLINE(MaxNewSize)) { 108 log_warning(gc, ergo)("MaxNewSize (" SIZE_FORMAT "k) is equal to or greater than the entire " 109 "heap (" SIZE_FORMAT "k). A new max generation size of " SIZE_FORMAT "k will be used.", 110 MaxNewSize/K, MaxHeapSize/K, smaller_max_new_size/K); 111 } 112 FLAG_SET_ERGO(size_t, MaxNewSize, smaller_max_new_size); 113 if (NewSize > MaxNewSize) { 114 FLAG_SET_ERGO(size_t, NewSize, MaxNewSize); 115 s._initial_young_size = NewSize; 116 } 117 } else if (MaxNewSize < s._initial_young_size) { 118 FLAG_SET_ERGO(size_t, MaxNewSize, s._initial_young_size); 119 } else if (!is_aligned(MaxNewSize, s._gen_alignment)) { 120 FLAG_SET_ERGO(size_t, MaxNewSize, align_down(MaxNewSize, s._gen_alignment)); 121 } 122 s._max_young_size = MaxNewSize; 123 } 124 125 if (NewSize > MaxNewSize) { 126 // At this point this should only happen if the user specifies a large NewSize and/or 127 // a small (but not too small) MaxNewSize. 128 if (FLAG_IS_CMDLINE(MaxNewSize)) { 129 log_warning(gc, ergo)("NewSize (" SIZE_FORMAT "k) is greater than the MaxNewSize (" SIZE_FORMAT "k). " 130 "A new max generation size of " SIZE_FORMAT "k will be used.", 131 NewSize/K, MaxNewSize/K, NewSize/K); 132 } 133 FLAG_SET_ERGO(size_t, MaxNewSize, NewSize); 134 s._max_young_size = MaxNewSize; 135 } 136 137 if (SurvivorRatio < 1 || NewRatio < 1) { 138 vm_exit_during_initialization("Invalid young gen ratio specified"); 139 } 140 141 if (OldSize < old_gen_size_lower_bound(s)) { 142 FLAG_SET_ERGO(size_t, OldSize, old_gen_size_lower_bound(s)); 143 } 144 if (!is_aligned(OldSize, s._gen_alignment)) { 145 FLAG_SET_ERGO(size_t, OldSize, align_down(OldSize, s._gen_alignment)); 146 } 147 148 if (FLAG_IS_CMDLINE(OldSize) && FLAG_IS_DEFAULT(MaxHeapSize)) { 149 // NewRatio will be used later to set the young generation size so we use 150 // it to calculate how big the heap should be based on the requested OldSize 151 // and NewRatio. 152 assert(NewRatio > 0, "NewRatio should have been set up earlier"); 153 size_t calculated_heapsize = (OldSize / NewRatio) * (NewRatio + 1); 154 155 calculated_heapsize = align_up(calculated_heapsize, s._heap_alignment); 156 FLAG_SET_ERGO(size_t, MaxHeapSize, calculated_heapsize); 157 s._max_heap_byte_size = MaxHeapSize; 158 FLAG_SET_ERGO(size_t, InitialHeapSize, calculated_heapsize); 159 s._initial_heap_byte_size = InitialHeapSize; 160 } 161 162 // Adjust NewSize and OldSize or MaxHeapSize to match each other 163 if (NewSize + OldSize > MaxHeapSize) { 164 if (FLAG_IS_CMDLINE(MaxHeapSize)) { 165 // Somebody has set a maximum heap size with the intention that we should not 166 // exceed it. Adjust New/OldSize as necessary. 167 size_t calculated_size = NewSize + OldSize; 168 double shrink_factor = (double) MaxHeapSize / calculated_size; 169 size_t smaller_new_size = align_down((size_t)(NewSize * shrink_factor), s._gen_alignment); 170 FLAG_SET_ERGO(size_t, NewSize, MAX2(young_gen_size_lower_bound(s), smaller_new_size)); 171 s._initial_young_size = NewSize; 172 173 // OldSize is already aligned because above we aligned MaxHeapSize to 174 // _heap_alignment, and we just made sure that NewSize is aligned to 175 // _gen_alignment. In initialize_flags() we verified that _heap_alignment 176 // is a multiple of _gen_alignment. 177 FLAG_SET_ERGO(size_t, OldSize, MaxHeapSize - NewSize); 178 } else { 179 FLAG_SET_ERGO(size_t, MaxHeapSize, align_up(NewSize + OldSize, s._heap_alignment)); 180 s._max_heap_byte_size = MaxHeapSize; 181 } 182 } 183 184 // Update NewSize, if possible, to avoid sizing the young gen too small when only 185 // OldSize is set on the command line. 186 if (FLAG_IS_CMDLINE(OldSize) && !FLAG_IS_CMDLINE(NewSize)) { 187 if (OldSize < s._initial_heap_byte_size) { 188 size_t new_size = s._initial_heap_byte_size - OldSize; 189 // Need to compare against the flag value for max since _max_young_size 190 // might not have been set yet. 191 if (new_size >= s._min_young_size && new_size <= MaxNewSize) { 192 FLAG_SET_ERGO(size_t, NewSize, new_size); 193 s._initial_young_size = NewSize; 194 } 195 } 196 } 197 198 always_do_update_barrier = UseConcMarkSweepGC; 199 200 DEBUG_ONLY(assert_flags(s);) 201 202 GenArguments::initialize_size_info(s); 203 } 204 205 // Values set on the command line win over any ergonomically 206 // set command line parameters. 207 // Ergonomic choice of parameters are done before this 208 // method is called. Values for command line parameters such as NewSize 209 // and MaxNewSize feed those ergonomic choices into this method. 210 // This method makes the final generation sizings consistent with 211 // themselves and with overall heap sizings. 212 // In the absence of explicitly set command line flags, policies 213 // such as the use of NewRatio are used to size the generation. 214 215 // Minimum sizes of the generations may be different than 216 // the initial sizes. An inconsistency is permitted here 217 // in the total size that can be specified explicitly by 218 // command line specification of OldSize and NewSize and 219 // also a command line specification of -Xms. Issue a warning 220 // but allow the values to pass. 221 void GenArguments::initialize_size_info(GenSettings& s) { 222 GCArguments::initialize_size_info(s); 223 224 s._initial_young_size = NewSize; 225 s._max_young_size = MaxNewSize; 226 s._initial_old_size = OldSize; 227 228 // Determine maximum size of the young generation. 229 230 if (FLAG_IS_DEFAULT(MaxNewSize)) { 231 s._max_young_size = scale_by_NewRatio_aligned(s._max_heap_byte_size, s._gen_alignment); 232 // Bound the maximum size by NewSize below (since it historically 233 // would have been NewSize and because the NewRatio calculation could 234 // yield a size that is too small) and bound it by MaxNewSize above. 235 // Ergonomics plays here by previously calculating the desired 236 // NewSize and MaxNewSize. 237 s._max_young_size = MIN2(MAX2(s._max_young_size, s._initial_young_size), MaxNewSize); 238 } 239 240 // Given the maximum young size, determine the initial and 241 // minimum young sizes. 242 243 if (s._max_heap_byte_size == s._initial_heap_byte_size) { 244 // The maximum and initial heap sizes are the same so the generation's 245 // initial size must be the same as it maximum size. Use NewSize as the 246 // size if set on command line. 247 s._max_young_size = FLAG_IS_CMDLINE(NewSize) ? NewSize : s._max_young_size; 248 s._initial_young_size = s._max_young_size; 249 250 // Also update the minimum size if min == initial == max. 251 if (s._max_heap_byte_size == s._min_heap_byte_size) { 252 s._min_young_size = s._max_young_size; 253 } 254 } else { 255 if (FLAG_IS_CMDLINE(NewSize)) { 256 // If NewSize is set on the command line, we should use it as 257 // the initial size, but make sure it is within the heap bounds. 258 s._initial_young_size = 259 MIN2(s._max_young_size, bound_minus_alignment(NewSize, s._initial_heap_byte_size, s._gen_alignment)); 260 s._min_young_size = bound_minus_alignment(s._initial_young_size, s._min_heap_byte_size, s._gen_alignment); 261 } else { 262 // For the case where NewSize is not set on the command line, use 263 // NewRatio to size the initial generation size. Use the current 264 // NewSize as the floor, because if NewRatio is overly large, the resulting 265 // size can be too small. 266 s._initial_young_size = 267 MIN2(s._max_young_size, MAX2(scale_by_NewRatio_aligned(s._initial_heap_byte_size, s._gen_alignment), NewSize)); 268 } 269 } 270 271 log_trace(gc, heap)("1: Minimum young " SIZE_FORMAT " Initial young " SIZE_FORMAT " Maximum young " SIZE_FORMAT, 272 s._min_young_size, s._initial_young_size, s._max_young_size); 273 274 // At this point the minimum, initial and maximum sizes 275 // of the overall heap and of the young generation have been determined. 276 // The maximum old size can be determined from the maximum young 277 // and maximum heap size since no explicit flags exist 278 // for setting the old generation maximum. 279 s._max_old_size = MAX2(s._max_heap_byte_size - s._max_young_size, s._gen_alignment); 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 s._min_old_size = s._gen_alignment; 290 s._initial_old_size = MIN2(s._max_old_size, MAX2(s._initial_heap_byte_size - s._initial_young_size, s._min_old_size)); 291 // _max_old_size 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 (s._initial_old_size > s._max_old_size) { 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 s._max_heap_byte_size); 305 s._initial_old_size = s._max_old_size; 306 } 307 308 s._min_old_size = MIN2(s._initial_old_size, s._min_heap_byte_size - s._min_young_size); 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 ((s._initial_old_size + s._initial_young_size) != s._initial_heap_byte_size) { 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 = s._initial_heap_byte_size - s._initial_old_size; 320 if (s._initial_heap_byte_size < s._initial_old_size) { 321 // Old want all memory, use minimum for young and rest for old 322 s._initial_young_size = s._min_young_size; 323 s._initial_old_size = s._initial_heap_byte_size - s._min_young_size; 324 } else if (desired_young_size > s._max_young_size) { 325 // Need to increase both young and old generation 326 s._initial_young_size = s._max_young_size; 327 s._initial_old_size = s._initial_heap_byte_size - s._max_young_size; 328 } else if (desired_young_size < s._min_young_size) { 329 // Need to decrease both young and old generation 330 s._initial_young_size = s._min_young_size; 331 s._initial_old_size = s._initial_heap_byte_size - s._min_young_size; 332 } else { 333 // The young generation boundaries allow us to only update the 334 // young generation. 335 s._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 s._min_young_size, s._initial_young_size, s._max_young_size); 340 } 341 342 // Write back to flags if necessary. 343 if (NewSize != s._initial_young_size) { 344 FLAG_SET_ERGO(size_t, NewSize, s._initial_young_size); 345 } 346 347 if (MaxNewSize != s._max_young_size) { 348 FLAG_SET_ERGO(size_t, MaxNewSize, s._max_young_size); 349 } 350 351 if (OldSize != s._initial_old_size) { 352 FLAG_SET_ERGO(size_t, OldSize, s._initial_old_size); 353 } 354 355 log_trace(gc, heap)("Minimum old " SIZE_FORMAT " Initial old " SIZE_FORMAT " Maximum old " SIZE_FORMAT, 356 s._min_old_size, s._initial_old_size, s._max_old_size); 357 358 DEBUG_ONLY(assert_size_info(s);) 359 } 360 361 #ifdef ASSERT 362 void GenArguments::assert_flags(const GenSettings& s) { 363 GCArguments::assert_flags(s); 364 assert(NewSize >= s._min_young_size, "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 % s._gen_alignment == 0, "NewSize alignment"); 368 assert(FLAG_IS_DEFAULT(MaxNewSize) || MaxNewSize % s._gen_alignment == 0, "MaxNewSize alignment"); 369 assert(OldSize + NewSize <= MaxHeapSize, "Ergonomics decided on incompatible generation and heap sizes"); 370 assert(OldSize % s._gen_alignment == 0, "OldSize alignment"); 371 } 372 373 void GenArguments::assert_size_info(const GenSettings& s) { 374 GCArguments::assert_size_info(s); 375 // GenArguments::initialize_size_info may update the MaxNewSize 376 assert(MaxNewSize < MaxHeapSize, "Ergonomics decided on incompatible maximum young and heap sizes"); 377 assert(NewSize == s._initial_young_size, "Discrepancy between NewSize flag and local storage"); 378 assert(MaxNewSize == s._max_young_size, "Discrepancy between MaxNewSize flag and local storage"); 379 assert(OldSize == s._initial_old_size, "Discrepancy between OldSize flag and local storage"); 380 assert(s._min_young_size <= s._initial_young_size, "Ergonomics decided on incompatible minimum and initial young gen sizes"); 381 assert(s._initial_young_size <= s._max_young_size, "Ergonomics decided on incompatible initial and maximum young gen sizes"); 382 assert(s._min_young_size % s._gen_alignment == 0, "_min_young_size alignment"); 383 assert(s._initial_young_size % s._gen_alignment == 0, "_initial_young_size alignment"); 384 assert(s._max_young_size % s._gen_alignment == 0, "_max_young_size alignment"); 385 assert(s._min_young_size <= bound_minus_alignment(s._min_young_size, s._min_heap_byte_size, s._gen_alignment), 386 "Ergonomics made minimum young generation larger than minimum heap"); 387 assert(s._initial_young_size <= bound_minus_alignment(s._initial_young_size, s._initial_heap_byte_size, s._gen_alignment), 388 "Ergonomics made initial young generation larger than initial heap"); 389 assert(s._max_young_size <= bound_minus_alignment(s._max_young_size, s._max_heap_byte_size, s._gen_alignment), 390 "Ergonomics made maximum young generation lager than maximum heap"); 391 assert(s._min_old_size <= s._initial_old_size, "Ergonomics decided on incompatible minimum and initial old gen sizes"); 392 assert(s._initial_old_size <= s._max_old_size, "Ergonomics decided on incompatible initial and maximum old gen sizes"); 393 assert(s._max_old_size % s._gen_alignment == 0, "_max_old_size alignment"); 394 assert(s._initial_old_size % s._gen_alignment == 0, "_initial_old_size alignment"); 395 assert(s._max_heap_byte_size <= (s._max_young_size + s._max_old_size), "Total maximum heap sizes must be sum of generation maximum sizes"); 396 assert(s._min_young_size + s._min_old_size <= s._min_heap_byte_size, "Minimum generation sizes exceed minimum heap size"); 397 assert(s._initial_young_size + s._initial_old_size == s._initial_heap_byte_size, "Initial generation sizes should match initial heap size"); 398 assert(s._max_young_size + s._max_old_size == s._max_heap_byte_size, "Maximum generation sizes should match maximum heap size"); 399 } 400 #endif // ASSERT