860d49db22
Reviewed-by: kbarrett, tschatzl
511 lines
18 KiB
Java
511 lines
18 KiB
Java
/*
|
|
* Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved.
|
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
*
|
|
* This code is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU General Public License version 2 only, as
|
|
* published by the Free Software Foundation.
|
|
*
|
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
* version 2 for more details (a copy is included in the LICENSE file that
|
|
* accompanied this code).
|
|
*
|
|
* You should have received a copy of the GNU General Public License version
|
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
*
|
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
|
* or visit www.oracle.com if you need additional information or have any
|
|
* questions.
|
|
*/
|
|
|
|
package nsk.share.gc;
|
|
|
|
import nsk.share.test.LocalRandom;
|
|
import java.io.PrintStream;
|
|
import nsk.share.gc.gp.GarbageProducer;
|
|
import nsk.share.gc.tree.*;
|
|
import nsk.share.gc.gp.MemoryStrategy;
|
|
import nsk.share.log.Log;
|
|
|
|
/**
|
|
* Different utility methods to work with memory objects.
|
|
*/
|
|
public final class Memory {
|
|
private static int bits = 0;
|
|
private static int referenceSize = 0;
|
|
private static int objectExtraSize = 0;
|
|
|
|
private Memory() {
|
|
}
|
|
|
|
private static int getBits() {
|
|
if (bits == 0)
|
|
bits = Integer.parseInt(System.getProperty("sun.arch.data.model"));
|
|
return bits;
|
|
}
|
|
|
|
/**
|
|
* Get size of one object reference.
|
|
*
|
|
* TODO: somehow determine the real value
|
|
*/
|
|
public static int getReferenceSize() {
|
|
if (referenceSize == 0)
|
|
referenceSize = (getBits() == 64) ? 8 : 4;
|
|
return referenceSize;
|
|
}
|
|
|
|
/**
|
|
* Get size of primitive type int.
|
|
*/
|
|
public static int getIntSize() {
|
|
return 4;
|
|
}
|
|
|
|
/**
|
|
* Get size of primitive type boolean.
|
|
*/
|
|
public static int getBooleanSize() {
|
|
return 1;
|
|
}
|
|
|
|
/**
|
|
* Get size of primitive type byte.
|
|
*/
|
|
public static int getByteSize() {
|
|
return 1;
|
|
}
|
|
|
|
/**
|
|
* Get size of primitive type char.
|
|
*/
|
|
public static int getCharSize() {
|
|
return 2;
|
|
}
|
|
|
|
/**
|
|
* Get size of primitive type short.
|
|
*/
|
|
public static int getShortSize() {
|
|
return 2;
|
|
}
|
|
|
|
/**
|
|
* Get size of primitive type long.
|
|
*/
|
|
public static int getLongSize() {
|
|
return 8;
|
|
}
|
|
|
|
/**
|
|
* Get size of primitive type float.
|
|
*/
|
|
public static int getFloatSize() {
|
|
return 4;
|
|
}
|
|
|
|
/**
|
|
* Get size of primitive type double.
|
|
*/
|
|
public static int getDoubleSize() {
|
|
return 8;
|
|
}
|
|
|
|
/**
|
|
* Get how many extra bytes an object occupies in the heap
|
|
* compared to sum of it's fields.
|
|
*
|
|
* TODO: somehow determine the real value
|
|
*/
|
|
public static int getObjectExtraSize() {
|
|
if (objectExtraSize == 0)
|
|
objectExtraSize = 2 * getReferenceSize();
|
|
return objectExtraSize;
|
|
}
|
|
/**
|
|
* Get how many extra bytes an array occupies in the heap
|
|
* compared to sum of it's fields.
|
|
*
|
|
* TODO: somehow determine the real value
|
|
*/
|
|
public static int getArrayExtraSize() {
|
|
return getObjectExtraSize();
|
|
}
|
|
|
|
/**
|
|
* Return size of reference object (SoftReference, WeakReference, PhantomReference)
|
|
*/
|
|
public static int getReferenceObjectSize() {
|
|
return getReferenceSize() + getObjectExtraSize();
|
|
}
|
|
|
|
/**
|
|
* Get an approximate length of array that will occupy a given memory.
|
|
*
|
|
* @param memory size of memory
|
|
* @param objectSize size of each object in array
|
|
* @return length of array
|
|
*/
|
|
public static int getArrayLength(long memory, long objectSize) {
|
|
int arrayExtraSize = getArrayExtraSize();
|
|
return (int) Math.min((memory - arrayExtraSize) / objectSize,
|
|
Integer.MAX_VALUE);
|
|
}
|
|
|
|
/**
|
|
* Get an approximate size of array of given length and object size.
|
|
*
|
|
* @param length length of arary
|
|
* @param objectSize size of object in array
|
|
* @return size of array
|
|
*/
|
|
public static long getArraySize(int length, long objectSize) {
|
|
return getArrayExtraSize() + length * objectSize;
|
|
}
|
|
|
|
/**
|
|
* Calculate approximate size of biggest of MemoryObjects.
|
|
*/
|
|
public static long getMemoryObjectSize(long size) {
|
|
return size + 2 * getReferenceSize() + getObjectExtraSize();
|
|
}
|
|
|
|
/**
|
|
* Calculate approximate size of linked list in memory.
|
|
*
|
|
* @param length length of list
|
|
* @param size size of object
|
|
* @return size
|
|
*/
|
|
public static long getListSize(int length, int size) {
|
|
return getObjectExtraSize() + length * (getReferenceSize() + getMemoryObjectSize(size));
|
|
}
|
|
|
|
/**
|
|
* Calculate length of linear or circular linked list.
|
|
*
|
|
* @param mobj head of list
|
|
* @return length of list
|
|
*/
|
|
public static int getListLength(LinkedMemoryObject mobj) {
|
|
LinkedMemoryObject tobj = mobj;
|
|
int length = 0;
|
|
do {
|
|
++length;
|
|
tobj = tobj.getNext();
|
|
} while (tobj != null && tobj != mobj);
|
|
return length;
|
|
}
|
|
|
|
/**
|
|
* Calculate length of array of linear or circular linked lists.
|
|
*
|
|
* @param mobjs array containting heads of lists
|
|
* @return length of all lists
|
|
*/
|
|
public static int getListsLength(LinkedMemoryObject[] mobjs) {
|
|
int length = 0;
|
|
for (int i = 0; i < mobjs.length; ++i) {
|
|
LinkedMemoryObject mobj = mobjs[i];
|
|
if (mobj != null)
|
|
length += getListLength(mobj);
|
|
}
|
|
return length;
|
|
}
|
|
|
|
/**
|
|
* Calculate size of all objects in linear or circular linked list.
|
|
*
|
|
* @param mobj head of list
|
|
* @return size of list
|
|
*/
|
|
public static long getListSize(LinkedMemoryObject mobj) {
|
|
LinkedMemoryObject tobj = mobj;
|
|
long size = 0;
|
|
do {
|
|
size += tobj.getSize();
|
|
tobj = tobj.getNext();
|
|
} while (tobj != null && tobj != mobj);
|
|
return size;
|
|
}
|
|
|
|
/**
|
|
* Calculate size of array of linear or circular linked lists.
|
|
*
|
|
* @param mobjs array containting heads of lists
|
|
* @return size of all lists
|
|
*/
|
|
public static long getListsSize(LinkedMemoryObject[] mobjs) {
|
|
long size = 0;
|
|
for (int i = 0; i < mobjs.length; ++i) {
|
|
LinkedMemoryObject mobj = mobjs[i];
|
|
if (mobj != null)
|
|
size += getListSize(mobj);
|
|
}
|
|
return size;
|
|
}
|
|
|
|
/**
|
|
* Create singly linked linear list of objects of fixed size.
|
|
*
|
|
* @param depth length of list
|
|
* @param size size of each object
|
|
* @return head of created list or null if depth = 0
|
|
*/
|
|
public static LinkedMemoryObject makeLinearList(int depth, int size) {
|
|
LinkedMemoryObject mobj = null;
|
|
for (int i = 0; i < depth; ++i)
|
|
mobj = new LinkedMemoryObject(size, mobj);
|
|
return mobj;
|
|
}
|
|
|
|
/**
|
|
* Create singly linked linear list of objects of varying size.
|
|
*
|
|
* @param depth length of list
|
|
* @param size maximum size of each object
|
|
* @return head of created list or null if depth = 0
|
|
*/
|
|
public static LinkedMemoryObject makeRandomLinearList(int depth, int size) {
|
|
if (depth == 0)
|
|
return null;
|
|
LinkedMemoryObject mobj = new LinkedMemoryObject(size);
|
|
for (int i = 0; i < depth - 1; ++i)
|
|
mobj = new LinkedMemoryObject(LocalRandom.nextInt(size), mobj);
|
|
return mobj;
|
|
}
|
|
|
|
/**
|
|
* Create singly linked circular linear list of objects of fixed size.
|
|
*
|
|
* @param depth length of list
|
|
* @param size size of each object
|
|
* @return head of created list or null if depth = 0
|
|
*/
|
|
public static LinkedMemoryObject makeCircularList(int depth, int size) {
|
|
if (depth == 0)
|
|
return null;
|
|
LinkedMemoryObject mobj = new LinkedMemoryObject(size);
|
|
LinkedMemoryObject tmpobj = mobj;
|
|
for (int i = 1; i < depth; i++)
|
|
mobj = new LinkedMemoryObject(size, mobj);
|
|
tmpobj.setNext(mobj);
|
|
return tmpobj;
|
|
}
|
|
|
|
/**
|
|
* Create singly linked circular linear list of objects of varying size.
|
|
*
|
|
* @param depth length of list
|
|
* @param size maximum size of each object
|
|
* @return head of created list or null if depth = 0
|
|
*/
|
|
public static LinkedMemoryObject makeRandomCircularList(int depth, int size) {
|
|
if (depth == 0)
|
|
return null;
|
|
LinkedMemoryObject mobj = new LinkedMemoryObject(size);
|
|
LinkedMemoryObject tmpobj = mobj;
|
|
for (int i = 0; i < depth - 1; i++)
|
|
mobj = new LinkedMemoryObject(LocalRandom.nextInt(size), mobj);
|
|
tmpobj.setNext(mobj);
|
|
return tmpobj;
|
|
}
|
|
|
|
/**
|
|
* Create new nonbranchy binary tree.
|
|
*
|
|
* Each node in the tree except leaves always has left son. A node
|
|
* will have right son with probability branchiness.
|
|
*
|
|
* @param numberOfNodes number of nodes
|
|
* @param branchiness branchiness
|
|
* @param size size of each node
|
|
* @return root of created tree
|
|
*/
|
|
public static LinkedMemoryObject makeNonbranchyTree(int numberOfNodes, float branchiness, int size) {
|
|
LinkedMemoryObject root = null;
|
|
LinkedMemoryObject current = null;
|
|
if (numberOfNodes == 0)
|
|
return null;
|
|
else if (numberOfNodes == 1)
|
|
return new LinkedMemoryObject(size);
|
|
else if (numberOfNodes == 2)
|
|
return new LinkedMemoryObject(size, makeNonbranchyTree(1, branchiness, size));
|
|
else {
|
|
if (LocalRandom.nextFloat() < branchiness) {
|
|
int numberOfLeftNodes = LocalRandom.nextInt(1, numberOfNodes - 1);
|
|
int numberOfRightNodes = numberOfNodes - 1 - numberOfLeftNodes;
|
|
return new LinkedMemoryObject(
|
|
size,
|
|
makeNonbranchyTree(numberOfLeftNodes, branchiness, size),
|
|
makeNonbranchyTree(numberOfRightNodes, branchiness, size)
|
|
);
|
|
} else {
|
|
return new LinkedMemoryObject(size, makeNonbranchyTree(numberOfNodes - 1, branchiness, size));
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Create a balanced tree of given height.
|
|
*
|
|
* @param height height of the tree
|
|
* @param size size of each node
|
|
* @return created tree
|
|
*/
|
|
public static Tree makeBalancedTree(int height, long size) {
|
|
return new Tree(makeBalancedTreeNode(height, size));
|
|
}
|
|
|
|
/**
|
|
* Get a number of nodes in balanced tree of given height.
|
|
*
|
|
* @param heigh height of the tree
|
|
* @return number of nodes
|
|
*/
|
|
public static int balancedTreeNodes(int height) {
|
|
if (height == 0)
|
|
return 0;
|
|
int n = 1;
|
|
while (height > 1) {
|
|
n *= 2;
|
|
height--;
|
|
}
|
|
return n * 2 - 1;
|
|
}
|
|
|
|
/**
|
|
* Get approximate memory size occupied by balanced tree
|
|
* of given height and given node size.
|
|
*
|
|
* @param height height of the tree
|
|
* @param nodeSize size of each node
|
|
* @return memory size
|
|
*/
|
|
public static long balancedTreeSize(int height, long nodeSize) {
|
|
return balancedTreeNodes(height) * nodeSize;
|
|
}
|
|
|
|
/**
|
|
* Get a height of balanced tree with given number of nodes.
|
|
*
|
|
* @param nodes number of nodes
|
|
* @return height of the tree
|
|
*/
|
|
public static int balancedTreeHeightFromNodes(int nodes) {
|
|
if (nodes == 0)
|
|
return 0;
|
|
int h = 1;
|
|
long n = 1;
|
|
while (n + n - 1 <= nodes) {
|
|
n = n + n;
|
|
h = h + 1;
|
|
}
|
|
return h - 1;
|
|
}
|
|
|
|
/**
|
|
* Get approximate height of balanced tree which will occupy
|
|
* given memory with given node size.
|
|
*
|
|
* @param memory memory size
|
|
* @param nodeSize size of each node
|
|
* @return approximate height of the tree
|
|
*/
|
|
public static int balancedTreeHeightFromMemory(long memory, long nodeSize) {
|
|
return balancedTreeHeightFromNodes((int) (memory / nodeSize));
|
|
}
|
|
|
|
/**
|
|
* Create balanced tree of given height and node size.
|
|
*
|
|
* @param height height of the tree
|
|
* @param size size of each node
|
|
* @return root of created tree
|
|
*/
|
|
public static TreeNode makeBalancedTreeNode(int height, long size) {
|
|
if (height == 0)
|
|
return null;
|
|
else
|
|
return new TreeNode(size, makeBalancedTreeNode(height - 1, size), makeBalancedTreeNode(height - 1, size));
|
|
}
|
|
|
|
/**
|
|
* Create balanced tree of given height and node size.
|
|
*
|
|
* @param height height of the tree
|
|
* @param size size of each node
|
|
* @return root of created tree
|
|
*/
|
|
public static TreeNode makeBalancedTreeNode(int height, long size, GarbageProducer gp) {
|
|
if (height == 0)
|
|
return null;
|
|
else
|
|
return new TreeNode(size, gp, makeBalancedTreeNode(height - 1, size), makeBalancedTreeNode(height - 1, size));
|
|
}
|
|
|
|
/**
|
|
* Determine if given tree is a balanced tree.
|
|
*
|
|
* @param tree tree
|
|
* @return true if tree is balanced
|
|
*/
|
|
public static boolean isBalancedTree(TreeNode tree) {
|
|
return
|
|
tree.getActualHeight() == tree.getHeight() &&
|
|
tree.getShortestPath() == tree.getHeight();
|
|
}
|
|
|
|
/**
|
|
* Fill an array of MemoryObject's with new objects of given size.
|
|
*
|
|
* @param array array
|
|
* @param count number of objects to create
|
|
* @param size size of each object
|
|
*/
|
|
public static void fillArray(MemoryObject[] array, int count, int size) {
|
|
for (int i = 0; i < count; ++i)
|
|
array[i] = new MemoryObject(size);
|
|
}
|
|
|
|
/**
|
|
* Fill an array of MemoryObject's with new objects of random size.
|
|
*
|
|
* @param array array
|
|
* @param count number of objects to create
|
|
* @param size maximum size of each object
|
|
*/
|
|
public static void fillArrayRandom(MemoryObject[] array, int count, int size) {
|
|
for (int i = 0; i < count; ++i)
|
|
array[i] = new MemoryObject(LocalRandom.nextInt(size));
|
|
}
|
|
|
|
/**
|
|
* Fill an array of MemoryObject's with new objects of random size.
|
|
*
|
|
* @param array array
|
|
* @param count number of objects to create
|
|
* @param size maximum size of each object
|
|
*/
|
|
public static void fillArrayRandom(LinkedMemoryObject[] array, int count, int size) {
|
|
for (int i = 0; i < count; ++i)
|
|
array[i] = new LinkedMemoryObject(LocalRandom.nextInt(size));
|
|
}
|
|
|
|
public static void dumpStatistics(PrintStream out) {
|
|
out.println(Runtime.getRuntime().freeMemory());
|
|
out.flush();
|
|
}
|
|
|
|
public static void dumpStatistics(Log log) {
|
|
log.info(Runtime.getRuntime().freeMemory());
|
|
}
|
|
|
|
public static void dumpStatistics() {
|
|
dumpStatistics(System.out);
|
|
}
|
|
}
|