package org.apache.cassandra.utils;
/*
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*/
import java.lang.management.ManagementFactory;
import java.lang.management.MemoryPoolMXBean;
import java.nio.ByteBuffer;
import org.github.jamm.MemoryMeter;
/**
* Modified version of the code from.
* https://github.com/twitter/commons/blob/master
* /src/java/com/twitter/common/objectsize/ObjectSizeCalculator.java
*
* Difference is that we don't use reflection.
*/
public class ObjectSizes
{
public static final MemoryLayoutSpecification SPEC = getEffectiveMemoryLayoutSpecification();
private static final MemoryMeter meter = new MemoryMeter().omitSharedBufferOverhead();
/**
* Describes constant memory overheads for various constructs in a JVM
* implementation.
*/
public interface MemoryLayoutSpecification
{
int getArrayHeaderSize();
int getObjectHeaderSize();
int getObjectPadding();
int getReferenceSize();
int getSuperclassFieldPadding();
}
/**
* Memory a class consumes, including the object header and the size of the fields.
* @param fieldsSize Total size of the primitive fields of a class
* @return Total in-memory size of the class
*/
public static long getFieldSize(long fieldsSize)
{
return roundTo(SPEC.getObjectHeaderSize() + fieldsSize, SPEC.getObjectPadding());
}
/**
* Memory a super class consumes, given the primitive field sizes
* @param fieldsSize Total size of the primitive fields of the super class
* @return Total additional in-memory that the super class takes up
*/
public static long getSuperClassFieldSize(long fieldsSize)
{
return roundTo(fieldsSize, SPEC.getSuperclassFieldPadding());
}
/**
* Memory an array will consume
* @param length Number of elements in the array
* @param elementSize In-memory size of each element's primitive stored
* @return In-memory size of the array
*/
public static long getArraySize(int length, long elementSize)
{
return roundTo(SPEC.getArrayHeaderSize() + length * elementSize, SPEC.getObjectPadding());
}
/**
* Memory a byte array consumes
* @param bytes byte array to get memory size
* @return In-memory size of the array
*/
public static long getArraySize(byte[] bytes)
{
return getArraySize(bytes.length, 1);
}
/**
* Memory a byte buffer consumes
* @param buffer ByteBuffer to calculate in memory size
* @return Total in-memory size of the byte buffer
*/
public static long getSize(ByteBuffer buffer)
{
long size = 0;
/* BB Class */
// final byte[] hb;
// final int offset;
// boolean isReadOnly;
size += ObjectSizes.getFieldSize(1L + 4 + ObjectSizes.getReferenceSize() + ObjectSizes.getArraySize(buffer.capacity(), 1));
/* Super Class */
// private int mark;
// private int position;
// private int limit;
// private int capacity;
size += ObjectSizes.getSuperClassFieldSize(4L + 4 + 4 + 4 + 8);
return size;
}
public static long roundTo(long x, int multiple)
{
return ((x + multiple - 1) / multiple) * multiple;
}
/**
* @return Memory a reference consumes on the current architecture.
*/
public static int getReferenceSize()
{
return SPEC.getReferenceSize();
}
private static MemoryLayoutSpecification getEffectiveMemoryLayoutSpecification()
{
final String dataModel = System.getProperty("sun.arch.data.model");
if ("32".equals(dataModel))
{
// Running with 32-bit data model
return new MemoryLayoutSpecification()
{
public int getArrayHeaderSize()
{
return 12;
}
public int getObjectHeaderSize()
{
return 8;
}
public int getObjectPadding()
{
return 8;
}
public int getReferenceSize()
{
return 4;
}
public int getSuperclassFieldPadding()
{
return 4;
}
};
}
final String strVmVersion = System.getProperty("java.vm.version");
final int vmVersion = Integer.parseInt(strVmVersion.substring(0, strVmVersion.indexOf('.')));
if (vmVersion >= 17)
{
long maxMemory = 0;
for (MemoryPoolMXBean mp : ManagementFactory.getMemoryPoolMXBeans())
{
maxMemory += mp.getUsage().getMax();
}
if (maxMemory < 30L * 1024 * 1024 * 1024)
{
// HotSpot 17.0 and above use compressed OOPs below 30GB of RAM
// total for all memory pools (yes, including code cache).
return new MemoryLayoutSpecification()
{
public int getArrayHeaderSize()
{
return 16;
}
public int getObjectHeaderSize()
{
return 12;
}
public int getObjectPadding()
{
return 8;
}
public int getReferenceSize()
{
return 4;
}
public int getSuperclassFieldPadding()
{
return 4;
}
};
}
}
/* Worst case we over count. */
// In other cases, it's a 64-bit uncompressed OOPs object model
return new MemoryLayoutSpecification()
{
public int getArrayHeaderSize()
{
return 24;
}
public int getObjectHeaderSize()
{
return 16;
}
public int getObjectPadding()
{
return 8;
}
public int getReferenceSize()
{
return 8;
}
public int getSuperclassFieldPadding()
{
return 8;
}
};
}
public static long measureDeep(Object pojo)
{
return meter.measureDeep(pojo);
}
}