com.gemstone.gemfire.internal.size.ReflectionSingleObjectSizer Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of gemfire-core Show documentation
Show all versions of gemfire-core Show documentation
TIBCO ComputeDB store based off Pivotal GemFireXD
/*
* Copyright (c) 2010-2015 Pivotal Software, Inc. All rights reserved.
*
* Licensed 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. See accompanying
* LICENSE file.
*/
package com.gemstone.gemfire.internal.size;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import com.gemstone.gemfire.internal.Assert;
import com.gemstone.gemfire.internal.SharedLibrary;
import com.gemstone.gemfire.pdx.internal.unsafe.UnsafeWrapper;
/**
* Figure out the size of an object using reflection. This class
* does not follow any object references, it just calculates the size
* of a flat object.
*
* @author dsmith
*
*/
public class ReflectionSingleObjectSizer implements SingleObjectSizer {
public static final int REFERENCE_SIZE = SharedLibrary.getReferenceSize();
public static final int OBJECT_SIZE = SharedLibrary.getObjectHeaderSize();
private static final UnsafeWrapper unsafe;
static {
UnsafeWrapper tmp = null;
try {
tmp = new UnsafeWrapper();
} catch (RuntimeException ignore) {
} catch (Error ignore) {
}
unsafe = tmp;
}
public static final ReflectionSingleObjectSizer INSTANCE =
new ReflectionSingleObjectSizer();
public long sizeof(Object object) {
return sizeof(object, true);
}
public long sizeof(Object object, boolean roundResult) {
Class clazz = object.getClass();
long size;
if(clazz.isArray()) {
if (unsafe != null) {
size = unsafe.arrayBaseOffset(clazz);
int arrayLength = Array.getLength(object);
if (arrayLength > 0) {
int typeSize = unsafe.arrayScaleIndex(clazz);
if (typeSize == 0) {
// the javadocs say that arrayScaleIndex may return 0.
// If it did then we use sizeType.
typeSize = sizeType(clazz.getComponentType());
}
size += (long)arrayLength * typeSize;
}
} else {
// not as accurate but does not use unsafe
size = OBJECT_SIZE + 4 /* for array length */;
int arrayLength = Array.getLength(object);
if (arrayLength > 0) {
size += (long)arrayLength * sizeType(clazz.getComponentType());
}
}
if (roundResult) {
size = roundUpSize(size);
}
return size;
} else {
return sizeof(clazz, roundResult);
}
}
public static long sizeof(Class clazz) {
return sizeof(clazz, true);
}
/**
* Since unsafe.fieldOffset(Field) will give us the offset to the first byte
* of that field all we need to do is find which of the non-static declared
* fields has the greatest offset.
*/
public static long sizeof(Class clazz, boolean roundResult) {
Assert.assertTrue(!clazz.isArray());
long size;
if (unsafe != null) {
Field lastField = null;
long lastFieldOffset = 0;
do {
Field[] fields = clazz.getDeclaredFields();
for(Field field: fields) {
if(!Modifier.isStatic(field.getModifiers())) {
long offset = unsafe.fieldOffset(field);
if (offset >= lastFieldOffset) {
lastFieldOffset = offset;
lastField = field;
}
}
}
if (lastField != null) {
// if we have found a field in a subclass then one of them will be the last field
// so just break without looking at super class fields.
break;
}
clazz = clazz.getSuperclass();
} while (clazz != null);
if (lastField != null) {
size = lastFieldOffset + sizeType(lastField.getClass());
} else {
// class with no fields
size = OBJECT_SIZE;
}
} else {
// This code is not as accurate as unsafe but gives an estimate of memory used.
// If it is wrong it will always under estimate because it does not account
// for any of the field alignment that the jvm does.
size = OBJECT_SIZE;
do {
Field[] fields = clazz.getDeclaredFields();
for(Field field: fields) {
if(!Modifier.isStatic(field.getModifiers())) {
size += sizeType(field.getClass());
}
}
clazz = clazz.getSuperclass();
} while (clazz != null);
}
if (roundResult) {
size = roundUpSize(size);
}
return size;
}
public static long roundUpSize(long size) {
//Round up to the nearest 8 bytes. Experimentally, this
//is what we've seen the sun 32 bit VM do with object size.
//See https://wiki.gemstone.com/display/rusage/Per+Entry+Overhead
long remainder = size % 8;
if (remainder != 0) {
size = size - remainder + 8;
}
return size;
}
private static int sizeType(Class t) {
if (t == Boolean.TYPE)
return 1;
else if (t == Byte.TYPE)
return 1;
else if (t == Character.TYPE)
return 2;
else if (t == Short.TYPE)
return 2;
else if (t == Integer.TYPE)
return 4;
else if (t == Long.TYPE)
return 8;
else if (t == Float.TYPE)
return 4;
else if (t == Double.TYPE)
return 8;
else if (t == Void.TYPE)
return 0;
else
return REFERENCE_SIZE;
}
public boolean isAgentAttached() {
return false;
}
}