1 /* 2 * Copyright (c) 2005, 2026, 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 package nsk.share.gc; 25 26 import nsk.share.test.LocalRandom; 27 import java.io.PrintStream; 28 import nsk.share.gc.gp.GarbageProducer; 29 import nsk.share.gc.tree.*; 30 import nsk.share.log.Log; 31 32 /** 33 * Different utility methods to work with memory objects. 34 */ 35 public final class Memory { 36 private static int bits = 0; 37 private static int referenceSize = 0; 38 private static int objectExtraSize = 0; 39 40 private static final boolean previewEnabled = 41 System.getProperty("test.java.opts", "").contains("--enable-preview") || 42 System.getProperty("test.vm.opts", "").contains("--enable-preview"); 43 44 45 private Memory() { 46 } 47 48 private static int getBits() { 49 if (bits == 0) 50 bits = Integer.parseInt(System.getProperty("sun.arch.data.model")); 51 return bits; 52 } 53 54 /** 55 * Get size of one object reference. 56 * 57 * TODO: somehow determine the real value 58 */ 59 public static int getReferenceSize() { 60 if (referenceSize == 0) 61 referenceSize = (getBits() == 64) ? 8 : 4; 62 return referenceSize; 63 } 64 65 public static boolean isPreviewEnabled() { 66 return previewEnabled; 67 } 68 69 public static boolean isValhallaEnabled() { 70 return previewEnabled; 71 } 72 73 /** 74 * Get size of primitive type int. 75 */ 76 public static int getIntSize() { 77 return 4; 78 } 79 80 /** 81 * Get size of primitive type boolean. 82 */ 83 public static int getBooleanSize() { 84 return 1; 85 } 86 87 /** 88 * Get size of primitive type byte. 89 */ 90 public static int getByteSize() { 91 return 1; 92 } 93 94 /** 95 * Get size of primitive type char. 96 */ 97 public static int getCharSize() { 98 return 2; 99 } 100 101 /** 102 * Get size of primitive type short. 103 */ 104 public static int getShortSize() { 105 return 2; 106 } 107 108 /** 109 * Get size of primitive type long. 110 */ 111 public static int getLongSize() { 112 return 8; 113 } 114 115 /** 116 * Get size of primitive type float. 117 */ 118 public static int getFloatSize() { 119 return 4; 120 } 121 122 /** 123 * Get size of primitive type double. 124 */ 125 public static int getDoubleSize() { 126 return 8; 127 } 128 129 /** 130 * Get size of Integer element in Integer array. 131 * If array is not flattened, the only reference size is returned, the referred values 132 * should be added manually in references are not null. 133 */ 134 public static int getIntegerArrayElementSize() { 135 136 if (!Memory.isValhallaEnabled()) { 137 return getReferenceSize(); 138 } 139 return 8; 140 } 141 142 /** 143 * Get size of Byte element in Byte array. 144 * If array is not flattened, the only reference size is returned, the referred values 145 * should be added manually in references are not null. 146 */ 147 public static int getByteArrayElementSize() { 148 149 if (!Memory.isValhallaEnabled()) { 150 return getReferenceSize(); 151 } 152 return 2; 153 } 154 155 /** 156 * Get size of Boolean element in Boolean array. 157 * If array is not flattened, the only reference size is returned, the referred values 158 * should be added manually in references are not null. 159 */ 160 public static int getBooleanArrayElementSize() { 161 if (!Memory.isValhallaEnabled()) { 162 return getReferenceSize(); 163 } 164 return 2; 165 } 166 167 168 169 /** 170 * Get how many extra bytes an object occupies in the heap 171 * compared to sum of it's fields. 172 * 173 * TODO: somehow determine the real value 174 */ 175 public static int getObjectExtraSize() { 176 if (objectExtraSize == 0) 177 objectExtraSize = 2 * getReferenceSize(); 178 return objectExtraSize; 179 } 180 /** 181 * Get how many extra bytes an array occupies in the heap 182 * compared to sum of it's fields. 183 * 184 * TODO: somehow determine the real value 185 */ 186 public static int getArrayExtraSize() { 187 return getObjectExtraSize(); 188 } 189 190 /** 191 * Return size of reference object (SoftReference, WeakReference, PhantomReference) 192 */ 193 public static int getReferenceObjectSize() { 194 return getReferenceSize() + getObjectExtraSize(); 195 } 196 197 /** 198 * Get an approximate length of array that will occupy a given memory. 199 * 200 * @param memory size of memory 201 * @param objectSize size of each object in array 202 * @return length of array 203 */ 204 public static int getArrayLength(long memory, long objectSize) { 205 int arrayExtraSize = getArrayExtraSize(); 206 int length = (int) Math.min((memory - arrayExtraSize) / objectSize, 207 Integer.MAX_VALUE); 208 return Math.max(length, 0); 209 } 210 211 /** 212 * Get an approximate size of array of given length and object size. 213 * 214 * @param length length of arary 215 * @param objectSize size of object in array 216 * @return size of array 217 */ 218 public static long getArraySize(int length, long objectSize) { 219 return getArrayExtraSize() + length * objectSize; 220 } 221 222 /** 223 * Calculate approximate size of biggest of MemoryObjects. 224 */ 225 public static long getMemoryObjectSize(long size) { 226 return size + 2 * getReferenceSize() + getObjectExtraSize(); 227 } 228 229 /** 230 * Calculate approximate size of linked list in memory. 231 * 232 * @param length length of list 233 * @param size size of object 234 * @return size 235 */ 236 public static long getListSize(int length, int size) { 237 return getObjectExtraSize() + length * (getReferenceSize() + getMemoryObjectSize(size)); 238 } 239 240 /** 241 * Calculate length of linear or circular linked list. 242 * 243 * @param mobj head of list 244 * @return length of list 245 */ 246 public static int getListLength(LinkedMemoryObject mobj) { 247 LinkedMemoryObject tobj = mobj; 248 int length = 0; 249 do { 250 ++length; 251 tobj = tobj.getNext(); 252 } while (tobj != null && tobj != mobj); 253 return length; 254 } 255 256 /** 257 * Calculate length of array of linear or circular linked lists. 258 * 259 * @param mobjs array containting heads of lists 260 * @return length of all lists 261 */ 262 public static int getListsLength(LinkedMemoryObject[] mobjs) { 263 int length = 0; 264 for (int i = 0; i < mobjs.length; ++i) { 265 LinkedMemoryObject mobj = mobjs[i]; 266 if (mobj != null) 267 length += getListLength(mobj); 268 } 269 return length; 270 } 271 272 /** 273 * Calculate size of all objects in linear or circular linked list. 274 * 275 * @param mobj head of list 276 * @return size of list 277 */ 278 public static long getListSize(LinkedMemoryObject mobj) { 279 LinkedMemoryObject tobj = mobj; 280 long size = 0; 281 do { 282 size += tobj.getSize(); 283 tobj = tobj.getNext(); 284 } while (tobj != null && tobj != mobj); 285 return size; 286 } 287 288 /** 289 * Calculate size of array of linear or circular linked lists. 290 * 291 * @param mobjs array containting heads of lists 292 * @return size of all lists 293 */ 294 public static long getListsSize(LinkedMemoryObject[] mobjs) { 295 long size = 0; 296 for (int i = 0; i < mobjs.length; ++i) { 297 LinkedMemoryObject mobj = mobjs[i]; 298 if (mobj != null) 299 size += getListSize(mobj); 300 } 301 return size; 302 } 303 304 /** 305 * Create singly linked linear list of objects of fixed size. 306 * 307 * @param depth length of list 308 * @param size size of each object 309 * @return head of created list or null if depth = 0 310 */ 311 public static LinkedMemoryObject makeLinearList(int depth, int size) { 312 LinkedMemoryObject mobj = null; 313 for (int i = 0; i < depth; ++i) 314 mobj = new LinkedMemoryObject(size, mobj); 315 return mobj; 316 } 317 318 /** 319 * Create singly linked linear list of objects of varying size. 320 * 321 * @param depth length of list 322 * @param size maximum size of each object 323 * @return head of created list or null if depth = 0 324 */ 325 public static LinkedMemoryObject makeRandomLinearList(int depth, int size) { 326 if (depth == 0) 327 return null; 328 LinkedMemoryObject mobj = new LinkedMemoryObject(size); 329 for (int i = 0; i < depth - 1; ++i) 330 mobj = new LinkedMemoryObject(LocalRandom.nextInt(size), mobj); 331 return mobj; 332 } 333 334 /** 335 * Create singly linked circular linear list of objects of fixed size. 336 * 337 * @param depth length of list 338 * @param size size of each object 339 * @return head of created list or null if depth = 0 340 */ 341 public static LinkedMemoryObject makeCircularList(int depth, int size) { 342 if (depth == 0) 343 return null; 344 LinkedMemoryObject mobj = new LinkedMemoryObject(size); 345 LinkedMemoryObject tmpobj = mobj; 346 for (int i = 1; i < depth; i++) 347 mobj = new LinkedMemoryObject(size, mobj); 348 tmpobj.setNext(mobj); 349 return tmpobj; 350 } 351 352 /** 353 * Create singly linked circular linear list of objects of varying size. 354 * 355 * @param depth length of list 356 * @param size maximum size of each object 357 * @return head of created list or null if depth = 0 358 */ 359 public static LinkedMemoryObject makeRandomCircularList(int depth, int size) { 360 if (depth == 0) 361 return null; 362 LinkedMemoryObject mobj = new LinkedMemoryObject(size); 363 LinkedMemoryObject tmpobj = mobj; 364 for (int i = 0; i < depth - 1; i++) 365 mobj = new LinkedMemoryObject(LocalRandom.nextInt(size), mobj); 366 tmpobj.setNext(mobj); 367 return tmpobj; 368 } 369 370 /** 371 * Create new nonbranchy binary tree. 372 * 373 * Each node in the tree except leaves always has left son. A node 374 * will have right son with probability branchiness. 375 * 376 * @param numberOfNodes number of nodes 377 * @param branchiness branchiness 378 * @param size size of each node 379 * @return root of created tree 380 */ 381 public static LinkedMemoryObject makeNonbranchyTree(int numberOfNodes, float branchiness, int size) { 382 LinkedMemoryObject root = null; 383 LinkedMemoryObject current = null; 384 if (numberOfNodes == 0) 385 return null; 386 else if (numberOfNodes == 1) 387 return new LinkedMemoryObject(size); 388 else if (numberOfNodes == 2) 389 return new LinkedMemoryObject(size, makeNonbranchyTree(1, branchiness, size)); 390 else { 391 if (LocalRandom.nextFloat() < branchiness) { 392 int numberOfLeftNodes = LocalRandom.nextInt(1, numberOfNodes - 1); 393 int numberOfRightNodes = numberOfNodes - 1 - numberOfLeftNodes; 394 return new LinkedMemoryObject( 395 size, 396 makeNonbranchyTree(numberOfLeftNodes, branchiness, size), 397 makeNonbranchyTree(numberOfRightNodes, branchiness, size) 398 ); 399 } else { 400 return new LinkedMemoryObject(size, makeNonbranchyTree(numberOfNodes - 1, branchiness, size)); 401 } 402 } 403 } 404 405 /** 406 * Create a balanced tree of given height. 407 * 408 * @param height height of the tree 409 * @param size size of each node 410 * @return created tree 411 */ 412 public static Tree makeBalancedTree(int height, long size) { 413 return new Tree(makeBalancedTreeNode(height, size)); 414 } 415 416 /** 417 * Get a number of nodes in balanced tree of given height. 418 * 419 * @param heigh height of the tree 420 * @return number of nodes 421 */ 422 public static int balancedTreeNodes(int height) { 423 if (height == 0) 424 return 0; 425 int n = 1; 426 while (height > 1) { 427 n *= 2; 428 height--; 429 } 430 return n * 2 - 1; 431 } 432 433 /** 434 * Get approximate memory size occupied by balanced tree 435 * of given height and given node size. 436 * 437 * @param height height of the tree 438 * @param nodeSize size of each node 439 * @return memory size 440 */ 441 public static long balancedTreeSize(int height, long nodeSize) { 442 return balancedTreeNodes(height) * nodeSize; 443 } 444 445 /** 446 * Get a height of balanced tree with given number of nodes. 447 * 448 * @param nodes number of nodes 449 * @return height of the tree 450 */ 451 public static int balancedTreeHeightFromNodes(int nodes) { 452 if (nodes == 0) 453 return 0; 454 int h = 1; 455 long n = 1; 456 while (n + n - 1 <= nodes) { 457 n = n + n; 458 h = h + 1; 459 } 460 return h - 1; 461 } 462 463 /** 464 * Get approximate height of balanced tree which will occupy 465 * given memory with given node size. 466 * 467 * @param memory memory size 468 * @param nodeSize size of each node 469 * @return approximate height of the tree 470 */ 471 public static int balancedTreeHeightFromMemory(long memory, long nodeSize) { 472 return balancedTreeHeightFromNodes((int) (memory / nodeSize)); 473 } 474 475 /** 476 * Create balanced tree of given height and node size. 477 * 478 * @param height height of the tree 479 * @param size size of each node 480 * @return root of created tree 481 */ 482 public static TreeNode makeBalancedTreeNode(int height, long size) { 483 if (height == 0) 484 return null; 485 else 486 return new TreeNode(size, makeBalancedTreeNode(height - 1, size), makeBalancedTreeNode(height - 1, size)); 487 } 488 489 /** 490 * Create balanced tree of given height and node size. 491 * 492 * @param height height of the tree 493 * @param size size of each node 494 * @return root of created tree 495 */ 496 public static TreeNode makeBalancedTreeNode(int height, long size, GarbageProducer gp) { 497 if (height == 0) 498 return null; 499 else 500 return new TreeNode(size, gp, makeBalancedTreeNode(height - 1, size), makeBalancedTreeNode(height - 1, size)); 501 } 502 503 /** 504 * Determine if given tree is a balanced tree. 505 * 506 * @param tree tree 507 * @return true if tree is balanced 508 */ 509 public static boolean isBalancedTree(TreeNode tree) { 510 return 511 tree.getActualHeight() == tree.getHeight() && 512 tree.getShortestPath() == tree.getHeight(); 513 } 514 515 /** 516 * Fill an array of MemoryObject's with new objects of given size. 517 * 518 * @param array array 519 * @param count number of objects to create 520 * @param size size of each object 521 */ 522 public static void fillArray(MemoryObject[] array, int count, int size) { 523 for (int i = 0; i < count; ++i) 524 array[i] = new MemoryObject(size); 525 } 526 527 /** 528 * Fill an array of MemoryObject's with new objects of random size. 529 * 530 * @param array array 531 * @param count number of objects to create 532 * @param size maximum size of each object 533 */ 534 public static void fillArrayRandom(MemoryObject[] array, int count, int size) { 535 for (int i = 0; i < count; ++i) 536 array[i] = new MemoryObject(LocalRandom.nextInt(size)); 537 } 538 539 /** 540 * Fill an array of MemoryObject's with new objects of random size. 541 * 542 * @param array array 543 * @param count number of objects to create 544 * @param size maximum size of each object 545 */ 546 public static void fillArrayRandom(LinkedMemoryObject[] array, int count, int size) { 547 for (int i = 0; i < count; ++i) 548 array[i] = new LinkedMemoryObject(LocalRandom.nextInt(size)); 549 } 550 551 public static void dumpStatistics(PrintStream out) { 552 out.println(Runtime.getRuntime().freeMemory()); 553 out.flush(); 554 } 555 556 public static void dumpStatistics(Log log) { 557 log.info(Runtime.getRuntime().freeMemory()); 558 } 559 560 public static void dumpStatistics() { 561 dumpStatistics(System.out); 562 } 563 } --- EOF ---