java解剖学:对象内存布局

零、快速入门

1. 每个java对象在内存中映射一个C++对象,C++对象只存储java对象头信息(mark和klass),C++头对象之后紧跟着java成员变量

2. java对象内存布局,主要是针对C++头对象之后的内存区域做编排

3. 常见的内存布局方式,是按照成员变量定义顺序依次分配内存地址(例如C++),但因为存在内存对齐机制,顺序分配会引入不少空白区域

4. hotspot虚拟机不使用变量声明顺序确定内存地址顺序,而是将相同类型的变量连续分布,同时长类型(double/long)在前,短类型(byte)靠后,从而减少内存对齐造成的空间浪费

一、概述

基于hotspot源码解释java对象内存布局。

java语言开发者借助JVM管理对象,向下屏蔽了底层内存使用细节,还具有强大gc的能力。但作为使用者,闲暇之余不禁在想,java对象在内存中具体是怎样的。工作中也遇到需要预估队列的内存开销以决定队列长度的情况,此时需要对java对象的内存占用情况有所了解。为此写下这篇关于java对象内存布局的文章,文章结构如下:

二、对象内存布局

1、netty里计算对象内存开销的逻辑

下面的代码摘自netty,用于估算对象内存开销。大致思路没有问题,但和底层实际内存布局还是有区别。其实从java语言的角度很难快速准确的计算对象内存开销,因为对象的内存布局受jvm实现、jvm版本、还有jvm启动参数的影响。

static {
   class2size.put(boolean.class, 4); // Probably an integer.
   class2size.put(byte.class, 1);
   class2size.put(char.class, 2);
   class2size.put(int.class, 4);
   class2size.put(short.class, 2);
   class2size.put(long.class, 8);
   class2size.put(float.class, 4);
   class2size.put(double.class, 8);
   class2size.put(void.class, 0);
}

public static int estimateSize(Object o) {
       if (o == null) {
           return 8;
       }

       int answer = 8 + estimateSize(o.getClass(), null);

       if (o instanceof byte[]) {
           answer += ((byte[]) o).length;
       } else if (o instanceof ByteBuffer) {
           answer += ((ByteBuffer) o).remaining();
       } else if (o instanceof CharSequence) {
           answer += ((CharSequence) o).length() << 1;
       } else if (o instanceof Iterable<?>) {
           for (Object m : (Iterable<?>) o) {
               answer += estimateSize(m);
           }
       }

       return align(answer);
   }

   private static int estimateSize(Class<?> clazz, Set<Class<?>> visitedClasses) {
       Integer objectSize = class2size.get(clazz);
       if (objectSize != null) {
           return objectSize;
       }

       if (visitedClasses != null) {
           if (visitedClasses.contains(clazz)) {
               return 0;
           }
       } else {
           visitedClasses = new HashSet<Class<?>>();
       }

       visitedClasses.add(clazz);

       int answer = 8; // Basic overhead.
       for (Class<?> c = clazz; c != null; c = c.getSuperclass()) {
           Field[] fields = c.getDeclaredFields();
           for (Field f : fields) {
               if ((f.getModifiers() & Modifier.STATIC) != 0) {
                   // Ignore static fields.
                   continue;
               }

               answer += estimateSize(f.getType(), visitedClasses);
          
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值