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 }