new一个Object对象占用多少内存?

Java的自动内存管理机制(automatic storage management system known as a garbage collector)省却了不少编码工做,大大地提升了Java的生产力,并且JVM的性能也愈来愈好,特别是G1的出现,改善了垃圾回收中stop the world的情况。html

 

也许不少人都没有考虑过这个问题,new一个Object对象到底占用多少内存呢( Object obj = new Object() )?java

 

这里很明确的是obj是一个指向对象的引用(reference - there are three kinds of reference types: class types,array types, and interface types),引用的长度决定了Java的寻址能力,32位的JDK是4字节,64位的JDK是8字节(指针未被压缩的状况下)。web

 

由于obj对象没有任何数据(field),会在堆上为它分配空间吗?若是分配空间,里面存储了什么内容?数据库

 

以面向对象的思惟来分析,对象封装了数据和行为,是一个统一的总体,虽然obj对象没有数据,可是有行为(Object类定义了12个方法)。当咱们执行完new操做后,obj的值为堆内存的地址,既然obj都指向一块内存了,说明是会在堆上为其分配空间的。编程

 

那么分配的空间有多大,存储了什么内容呢?The Java Virtual Machine Specification Java SE 7 EditionThe Java Language Specification Java SE 7 Edition里面没有找到相关的描述,这极可能是属于JVM实现自由控制的范畴了。咱们能够利用JDK自带的工具jvisualvm.exe来查看分配的空间有多大。为了方便在jvisualvm中查看对象占多少内存,这里使用一个私有的静态内部类EmptyObject来替代Object,由于类定义为空,因此能够等同对待EmptyObject和Object。架构

 

/**
 * 构造一个无任何字段的空对象占多少内存
 * @author 杨尚川
 */
public class EmptyTest {
    
    public static void main(String[] args) throws InterruptedException{
        //加到集合中,使垃圾没法回收
        List<EmptyObject> emptys = new ArrayList<>();
        for(int i=0;i<100;i++){
            emptys.add(new EmptyObject());
        }
        //打开jvisualvm,查看EmptyObject的大小为16字节
        Thread.sleep(60*1000);
    }
    private static class EmptyObject{}
}

 

 

咱们在这里面经过new不一样的对象数(for循环次数),来分析内存占用,new 1个对象是16字节,new 2个对象是32字节,new 100个对象是1600字节,经过不少次的尝试,咱们从jvisualvm里面能够看到 字节数=对象数*16 ,咱们有理由相信对象数跟字节数的线性关系。从这里能够看出,jvisualvm显示的内存占用跟引用的4字节或8字节是没有关系的,也就是说,jvisualvm显示的是堆内存占用,这也很好理解,毕竟全部引用的字节占用是固定的。8字节是引用,16字节是堆内存,总共是8+16=24字节,因此new一个Object对象占用8+16=24字节(64位JDK)oracle

 

若是JDK是32位,按如上分析方法可知new一个Object对象占用4+8=12字节(32位JDK),以下图所示:ide

 

64位JDK:

32位JDK:

工具

 

 

那么分配的16字节(8字节)的堆内存中存储了什么内容呢?当咱们Object obj = new Object();的时候,在栈内存中有一个引用obj,他多是32位也多是64位,obj实质只是一个内存地址,那么当咱们调用obj.xxx()的时候,JVM怎么知道obj是哪一个类的实例呢?因此,能够大胆地推测,obj对象的16字节(8字节)的堆内存中记录了对象属于哪一个类的信息,问题是这16字节(8字节)的结构是什么样的?不清楚!布局

 

不过咱们仍然能够大胆地猜想一下,经过上面的64位和32位的堆内存大小对比分析发现,堆内存分配的大小是引用的两倍,上面咱们已经猜想堆内存中会记录对象是哪一个类的实例,如何记录呢?由于类对象是放置在方法区的,类对象自己也是一个对象,所以能够经过一个引用指向它,因此堆内存有可能就是放置了两个引用,指向两个对象。分析到这里,事情就比较明朗了,堆内存中可能就放置了两个内存地址,一个指向EmptyObject.class(在实验代码中用EmptyObject来代替Object),一个指向什么呢?不清楚!

 

Inside the Java 2 Virtual Machine 2nd by Bill Venners的5.3.5中有这么一段描述:

 

The Java virtual machine specification is silent on how objects should be represented on the heap. Object representation--an integral aspect of the overall design of the heap and garbage collector--is a decision of implementation designers. 

 

好了,事情最终清楚了,JVM规范并无规定Java对象在堆中是如何表示的,对象的表示是堆和垃圾收集器的总体设计的一个组成部分,这是由JVM实现的设计师来决定的。 所以,若是咱们真的想搞清楚对象是如何表示的,那么须要查询HotSpot VM或是其余JVM实现的相关资料。

 

在淘宝工程师莫枢(撒迦)的《JVM分享》PPT的第112页介绍了“HotSpot中的Java对象布局”,这真是如今关心的内容,经过PPT的介绍说明前面的猜想是对的,以下图所示:



 

 

 

 

 

 

 

咱们研究new一个Object对象占多少内存可能没什么实际意义,由于咱们在编程的时候就能够肯定对象树,基本能够肯定对象大小,除了变长字段,固然,变长字段咱们通常也会有长度限制。因此咱们真正关心的是全部数据最终的大小,也就是数据库的大小。

 

面向对象的分析、设计和编程都把“封装”奉为圭臬,“分层”更是架构设计中相当重要的设计准则。由于只有这样,才能实现基本的解耦、让协做分工成为可能,知足工业要求的最大化生产力的最终目标。

 

那么这种没有什么实际意义的问题为何要研究呢?我以为只能用三个字来形容:好奇心好奇心是驱使咱们研究技术的强大推力,当咱们工做了不少年,尤为是在不重视技术的公司,咱们对技术还有激情吗?保持一颗敏感好奇的心,也许技术之路能够走的更长更远。

 

这篇文章的重点是展现一种分析问题的思路,要大胆猜想,当心求证,追本溯源,引经据典。求证方式:查找标准规范、查找经典权威书籍、本身作实验、查找源代码等。

 

参考资料:

一、Java™ Virtual Machine Technology

二、The Java Virtual Machine Specification Java SE 7 Edition

三、The Java Language Specification Java SE 7 Edition

四、Inside the Java 2 Virtual Machine 2nd by Bill Venners

五、JVM分享

六、http://www.javamex.com/classmexer/

相关文章
相关标签/搜索