All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.gemstone.gemfire.internal.size.ReflectionSingleObjectSizer Maven / Gradle / Ivy

There is a newer version: 2.0-BETA
Show newest version
/*
 * 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;
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy