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 }