你的java对象占用了多少内存?

Java对象内存结构

在这里插入图片描述
没什么可说的,可查看下方的相关文档Java对象的内存布局

只是需要多补充一个知识点,数组对象头(object header) 在64位虚拟机中是要求8字节对齐的,而不仅仅是object整个对象要求8字节对齐。但是这个限制在32位虚拟机中是没有的


虚拟机信息常量

  • JRE_IS_64BIT 是否是64位虚拟机
  • NUM_BYTES_OBJECT_HEADER 对象(非数组对象)头占用的大小,不考虑内部属性以及对齐情况
  • NUM_BYTES_ARRAY_HEADER 数组对象头的大小(无内容,但考虑对齐),相比上面,多了些内存来描述数组长度
  • NUM_BYTES_OBJECT_ALIGNMENT 对象的对齐基线,一般是8字节
  • COMPRESSED_REFS_ENABLED 是否开启指针压缩,jdk8后默认开启
  • NUM_BYTES_OBJECT_REF 引用对象指针需要的字节个数

上述常量的计算,可参考
https://github.com/gsonkeno/lucene-8.8.2-maven-notes/blob/master/core/src/main/java/org/apache/lucene/util/Constants.java#L62

https://github.com/gsonkeno/lucene-8.8.2-maven-notes/blob/master/core/src/main/java/org/apache/lucene/util/RamUsageEstimator.java#L137

shallow size & retained size

大小测量分为三种:

  • 浅层大小(Shallow Size) 不包括引用数组和实例的大小,而只包括相应指针的大小。 对于将所有对象都放在堆上的第一个对象集,浅层大小等于保留大小和深层大小。

  • 保留大小(Retained Size)计算为浅层大小加上如果要删除当前对象集, 将被垃圾回收的所有对象的总大小。这个大小告诉您在一个对象集后面实际有多少内存。

  • 深层大小(Deep Size)计算为浅层大小加上所有引用对象的总大小。 在极端情况下,这个值可能占整个堆的很大百分比。
    官方文档介绍

lucene中关于 shallow size的计算主要有以下几个方法

  /** Returns the shallow size in bytes of the Object[] object. */
  // Use this method instead of #shallowSizeOf(Object) to avoid costly reflection
  // 获取对象(非基本类型)数组的shallowSize, 避免了反射,消耗更小
  public static long shallowSizeOf(Object[] arr) {
    // NUM_BYTES_ARRAY_HEADER 数组的对象头要求8字节对齐
    // NUM_BYTES_OBJECT_REF 引用对象指针需要4字节
    return alignObjectSize((long) NUM_BYTES_ARRAY_HEADER + (long) NUM_BYTES_OBJECT_REF * arr.length);
  }
---------------------
   /**
   * Return shallow size of any <code>array</code>.
   */
  private static long shallowSizeOfArray(Object array) {
    long size = NUM_BYTES_ARRAY_HEADER;
    final int len = Array.getLength(array);
    if (len > 0) {
      Class<?> arrayElementClazz = array.getClass().getComponentType();
      if (arrayElementClazz.isPrimitive()) {
        // 基本类型
        size += (long) len * primitiveSizes.get(arrayElementClazz);
      } else {
        // 对象指针
        size += (long) NUM_BYTES_OBJECT_REF * len;
      }
    }
    return alignObjectSize(size);
  }
------------------------------------
/**
   * Returns the shallow instance size in bytes an instance of the given class would occupy.
   * This works with all conventional classes and primitive types, but not with arrays
   * (the size then depends on the number of elements and varies from object to object).
   *  1. 不处理数组,只处理对象(包括基本类型)
   *  2. 计算对象shallow size时只处理成员变量,不考虑类变量, 还有考虑到类继承关系
   *  3. 最后的结果要8字节对齐
   * @see #shallowSizeOf(Object)
   * @throws IllegalArgumentException if {@code clazz} is an array class. 
   */
  public static long shallowSizeOfInstance(Class<?> clazz) {
    if (clazz.isArray())
      throw new IllegalArgumentException("This method does not work with array classes.");
    if (clazz.isPrimitive())
      return primitiveSizes.get(clazz);
    // maskword 在64位虚拟机下占用8字节,klazz 指针占用4字节,故对象头12字节
    long size = NUM_BYTES_OBJECT_HEADER;

    // Walk type hierarchy
    for (;clazz != null; clazz = clazz.getSuperclass()) {
      final Class<?> target = clazz;
      final Field[] fields = AccessController.doPrivileged(new PrivilegedAction<Field[]>() {
        @Override
        // 获取公开、私有属性都可以,但是排除继承属性
        public Field[] run() {
          return target.getDeclaredFields();
        }
      });
      for (Field f : fields) {
        if (!Modifier.isStatic(f.getModifiers())) { // 忽略静态属性
          size = adjustForField(size, f);
        }
      }
    }
    return alignObjectSize(size);    
  }
  

相关文档

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值