`
zhang_xzhi_xjtu
  • 浏览: 524392 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

java对象的大小_基础知识

阅读更多
引言
Java的对象被jvm管理,单个对象如何布局,大小如何,程序员可以不用关心。
但是,掌握一些相关的知识,可以让我们对应用中使用的对象大小有一个大致的估计,做到心中有数,当遇到内存敏感型应用时,可以通过适当的参数调节和应用优化减少内存占用。
另外,just for fun。


声明
以下讨论大部分都是基于32bits Java Hotspot VM,关于64bits的会特殊声明。
本文查看java对象的内存输出来自工具包memoryutil
http://zhang-xzhi-xjtu.iteye.com/admin/blogs/2116347

Java对象内存组成
对象内存由以下几部分组成:Object header + primitive fields + reference fields + padding

Object header :
对象头。Hotspot中,一般对象(非数组对象)为8bytes,数组对象为12bytes。

primitive fields :
boolean byte 1
char short 2
int float 4
long double 8

reference fields :
4 bytes

padding :
为了内存对齐的填充字节。
Hotspot中,对象占据的内存是8字节的整数倍。如果不是,则加padding到8字节的整数倍。注意,padding不一定是padding到所有field之后,field有可能重新排序,以满足一定的对齐规则,padding也有可能插入到不同的地方,参见下文的例子。

shallow size和full size

class A{
	int id;
	String str;
}

我们计算new A()占据的内存时:
对象头, id(primitive)所占据的内存,str的reference内存,padding。为shallow size。
对象头, id(primitive)所占据的内存, str的reference内存,padding,str实例本身所占据的内存(full size)。为full size。



简单普通对象例子
一个new Object()占据8bytes,只有对象头。
shallow size=full size=8


class ObjectWithOneBooleanField {
    boolean b;
}
一个new ObjectWithOneBooleanField()占据16bytes.
shallow size=full size=8(对象头)+1(boolean)+7(padding)=16


当一个class定义了8个boolean的field。一个对象还是占据16bytes。这种情况下无padding。
shallow size=full size=8(对象头)+8(boolean*8)=16。


class A {
    boolean val0;
    long    val1;
    int     val2;
}
一个new A()占据24bytes.
shallow size=full size=8(对象头)+1(boolean)+8(long)+4(int)+3(padding)=24



数组及例子
数组是特殊的对象。对象头为12。4bytes保存length。
多维数组不过就是数组的数组。

一维primitive数组

new byte[0]
shallow size=full size=12(对象头)+4(padding)=16


new byte[4]
shallow size=full size=12(对象头)+4(byte*4)=16


new byte[5]
shallow size=full size=12(对象头)+5(byte*5)+7(padding)=24

一维reference数组
new Object[] {}
shallow size=full size=12(对象头)+4(padding)=16


new Object[] { new Object(), new Object() }
shallow size=12(对象头)+8(reference*2)+4(padding)=24
full size=24(shallow size)+16(2个空object的内存,每个8bytes)=40

二维数组
new Object[][] {
new Object[] { new Object() },
new Object[] { new Object(), new Object() }
}
shallow size=12(对象头)+8(reference*2)+4(padding)=24

对new Object[] { new Object() }
shallow size=12(对象头)+4(reference)=16
full size=16(shallow size)+8(空对象大小)=24

对new Object[] { new Object(), new Object() }
Full size=40(前文计算过)

合起来 full size=24+24+40=88


Field重排序
我们来看一个例子。

class ClassWithManyFields {
    boolean val0;
    long    val1;
    int     val2;
    long    val3;
    boolean val4;
    long    val5;
}



ClassWithManyFields
----------------------------------------------------------------
object class info : allen.memoryutil.dirver.ClassWithManyFields
object identityHashCode : 10851992
in parent info : root object
shallow size = 40
full size = 40
-----------shallow size detail.-----------------
headerType = NormalHeader size = 8
offset : 8 size = 8 long allen.memoryutil.dirver.ClassWithManyFields.val1
offset : 16 size = 8 long allen.memoryutil.dirver.ClassWithManyFields.val3
offset : 24 size = 8 long allen.memoryutil.dirver.ClassWithManyFields.val5
offset : 32 size = 4 int allen.memoryutil.dirver.ClassWithManyFields.val2
offset : 36 size = 1 boolean allen.memoryutil.dirver.ClassWithManyFields.val0
offset : 37 size = 1 boolean allen.memoryutil.dirver.ClassWithManyFields.val4
padding size = 2
-----------end of shallow size detail.----------
----------------------------------------------------------------

可以看出,field被重新排序,以保证K长度的数据类型地址都是K的整数倍。


类继承关系对内存布局的影响
class Father {
    byte father_byte_0;
    long father_long;
    byte father_byte_1;
}

class Child extends Father {
    byte child_byte_0;
    long child_long;
    byte child_byte_1;
}


Child
----------------------------------------------------------------
object class info : allen.memoryutil.dirver.Child
object identityHashCode : 15244180
in parent info : root object
shallow size = 32
full size = 32
-----------shallow size detail.-----------------
headerType = NormalHeader size = 8
offset : 8 size = 8 long allen.memoryutil.dirver.Father.father_long
offset : 16 size = 1 byte allen.memoryutil.dirver.Father.father_byte_0
offset : 17 size = 1 byte allen.memoryutil.dirver.Father.father_byte_1
offset : 20 size = 1 byte allen.memoryutil.dirver.Child.child_byte_0
offset : 21 size = 1 byte allen.memoryutil.dirver.Child.child_byte_1
offset : 24 size = 8 long allen.memoryutil.dirver.Child.child_long
padding size = 4
-----------end of shallow size detail.----------
----------------------------------------------------------------

可以看到,父类的field先单独排列(有重排序),然后才是子类的field排列(有重排序)。


如何合法浪费内存
理解了内存对齐和父类的field单独排列,我们可以合法的构造浪费内存的对象。
class C_A {
    byte a_byte;
}

class C_B extends C_A {
    long b_long;
}

class C_C extends C_B {
    byte c_byte;
}

class C_D extends C_C {
    long d_long;
}


C_D
----------------------------------------------------------------
object class info : allen.memoryutil.dirver.C_D
object identityHashCode : 30377347
in parent info : root object
shallow size = 40
full size = 40
-----------shallow size detail.-----------------
headerType = NormalHeader size = 8
offset : 8 size = 1 byte allen.memoryutil.dirver.C_A.a_byte
offset : 16 size = 8 long allen.memoryutil.dirver.C_B.b_long
offset : 24 size = 1 byte allen.memoryutil.dirver.C_C.c_byte
offset : 32 size = 8 long allen.memoryutil.dirver.C_D.d_long
padding size = 14
-----------end of shallow size detail.----------
----------------------------------------------------------------

可以看到,由于类型在继承体系中,field是byte和long间隔定义,导致padding比较大。
当类的继承链比较长时,则最多可以浪费7/16=43%的内存。


32位jvm和64位jvm
64bits JVM和32bits相比变化如下:




对象占用的内存大小受到VM参数UseCompressedOops的影响。

开启(-XX:+UseCompressedOops) 可以压缩指针。
关闭(-XX:-UseCompressedOops) 可以关闭压缩指针。

原理:
4bytes引用(地址编码),当寻址单位为1 byte时,寻址空间为4G空间。
由于java对象都是8bytes对齐的,因此,所有java对象地址的低3bits都是0,有点浪费。
如果寻址单位从1byte改为8bytes,则可以去除该浪费。
4bytes引用(地址编码),当寻址单位为8 byte时,寻址空间为32G空间。

可以看到,压缩指针技术只适用于java堆大小<=32G的情况。

UseCompressedOops默认开启规则:
Compressed oops is supported and enabled by default in Java SE 6u23 and later. In Java SE 7, use of compressed oops is the default for 64-bit JVM processes when -Xmx isn't specified and for values of -Xmx less than 32 gigabytes. For JDK 6 before the 6u23 release, use the -XX:+UseCompressedOops flag with the java command to enable the feature.

memoryutil详情输出简要说明
"abcd"字符串的详情例子
----------------------------------------------------------------
object class info : java.lang.String                             //对象类型
object identityHashCode : 4875744                                //对象identityHashCode
in parent info : root object
shallow size = 24                                                //对象shallow size
full size = 48                                                   //对象full size
full padding size = 4                                            //对象full padding size
-----------shallow size detail.-----------------                 //对象shallow size的详情信息
headerType = NormalHeader size = 8                               //普通对象头,大小为8
offset : 8 size = 4 private final char[] java.lang.String.value  //value field的offset为8,大小为4。
offset : 12 size = 4 private final int java.lang.String.offset   //offset field的offset为12,大小为4。
offset : 16 size = 4 private final int java.lang.String.count    //count field的offset为16,大小为4。
offset : 20 size = 4 private int java.lang.String.hash           //hash field的offset为20,大小为4。
padding size = 0                                                 //padding为0。
-----------end of shallow size detail.----------
                                                                 //该字符串引用的char[]详情信息
    object class info : char[]                                   
    object identityHashCode : 15672056                            
    in parent info : private final char[] java.lang.String.value in parent.  //对象在被引用对象中的位置信息。
    shallow size = 24
    full size = 24
    full padding size = 4
    -----------shallow size detail.-----------------
    headerType = ArrayHeader size = 12                           //数组对象头,大小为12
    compType = char arrayLength = 4 size = ( 2 * 4 ) = 8         //数组的类型为char,长度为4,大小为8。
    padding size = 4                                             //padding为4。
    -----------end of shallow size detail.----------
----------------------------------------------------------------


参考
http://www.javamex.com/tutorials/memory/index.shtml
http://docs.oracle.com/javase/7/docs/technotes/guides/vm/performance-enhancements-7.html#compressedOop

分享到:
评论

相关推荐

    Java语言基础下载

    对象的基础知识 522 this关键词 523 new运算符 523 常用对象的属性和方法 525 算术函数的math对象 527 创建新对象 529 JavaScript中的数组 532 实例 535 文档对象功能及其作用 538 document中三个主要的对象 539 ...

    JAVA上百实例源码以及开源项目

     Java生成密钥、保存密钥的实例源码,通过本源码可以了解到Java如何产生单钥加密的密钥(myKey)、产生双钥的密钥对(keyPair)、如何保存公钥的字节数组、保存私钥到文件privateKey.dat、如何用Java对象序列化保存私钥...

    JAVA上百实例源码以及开源项目源代码

     Java生成密钥、保存密钥的实例源码,通过本源码可以了解到Java如何产生单钥加密的密钥(myKey)、产生双钥的密钥对(keyPair)、如何保存公钥的字节数组、保存私钥到文件privateKey.dat、如何用Java对象序列化保存私钥...

    Java基础入门及提高.pdf

    《Java基础入门及提高》,整理:yyc、spirit。PDF 格式,大小 4.8 MB,非影印版。 前言: 同人类任何语言一样,Java 为我们提供了一种表达思想的方式。如操作得当,同其他方式相比,随着问题变得愈大和愈复杂,这种...

    软件工程师Java班课程

    设计基础 J2sdk基础、Java 面向对象基础、Java API使用、数据结构及算法基础、Java高级类特性、异常处理。 掌握Java语言规范、面向对象编程基础(OOA/OOP) J2SE平台Java程序设计 Java AWT图形界面程序开发,Swing...

    JAVA面试题最全集

    一、Java基础知识 1.Java有那些基本数据类型,String是不是基本数据类型,他们有何区别。 2.字符串的操作: 写一个方法,实现字符串的反转,如:输入abc,输出cba 写一个方法,实现字符串的替换,如:输入...

    基于Java的视频会议系统(软件程序+WORD论文文档).zip

    在这基础上,由于相关音频、视频,所以还要涉及到JAVA的多媒体技术的相关知识,即JMF (Java Media Framework)。利用JAVA的这个组件,我们可以方便的处理多媒体文件,并基于RTP协议进行实时传输。 2.1.2 操作可行性...

    java面试笔试题大汇总

    JAVA相关基础知识 1、面向对象的特征有哪些方面 1.抽象: 抽象就是忽略一个主题中与当前目标无关的那些方面,以便更充分地注意与当前目标有关的方面。抽象并不打算了解全部问题,而只是选择其中的一部分,暂时...

    AIC的Java课程1-6章

    希望大家喜欢 &lt;br&gt;如果大家觉得好我继续发 &lt;br&gt;课程定位 “Java程序”课程覆盖SCJP认证所要求的知识点,是J2EE课程体系中的基础课程。本课程面向的学员应该具有基本的编程概念,能够编写简单的程序,并学习...

    java 面试题 总结

    JAVA相关基础知识 1、面向对象的特征有哪些方面 1.抽象: 抽象就是忽略一个主题中与当前目标无关的那些方面,以便更充分地注意与当前目标有关的方面。抽象并不打算了解全部问题,而只是选择其中的一部分,暂时不用...

    Java并发编程(学习笔记).xmind

    基础知识 线程安全性 定义 当多个线程访问某个类时,这个类始终能表现出正确的行为,那么就称这个类是线程安全的 无状态对象一定是线程安全的,大多数Servlet都是无状态的 原子性 一组不可分割...

    java面试题

    JAVA相关基础知识 1、面向对象的特征有哪些方面 1.抽象: 抽象就是忽略一个主题中与当前目标无关的那些方面,以便更充分地注意与当前目标有关的方面。抽象并不打算了解全部问题,而只是选择其中的一部分,暂时不用...

    Java课程设计-21点小游戏.docx

    其目的在于通过实践加深学生对面向对象程序设计的理论、方法和基础知识的理解,掌握使用Java语言进行面向对象设计的基本方法,提高运用面向对象知识分析实际问题、解决实际问题的能力,提高学生的应用能力。...

    Java完美编程(第3版).pdf

     7.1 有关继承的基础知识   7.2 封装和继承   7.3 继承编程   小结   自测题参考答案   编程项目 第8章 多态性和抽象类 第9章 异常处理 第10章 文件i/o 第11章 递归 第12章 uml和模式 第13章 ...

    Java课程设计-21点小游戏(2).docx

    其目的在于通过实践加深学生对面向对象程序设计的理论、方法和基础知识的理解,掌握使用Java语言进行面向对象设计的基本方法,提高运用面向对象知识分析实际问题、解决实际问题的能力,提高学生的应用能力。...

    Java课程设计-21点小游戏(1).docx

    其目的在于通过实践加深学生对面向对象程序设计的理论、方法和基础知识的理解,掌握使用Java语言进行面向对象设计的基本方法,提高运用面向对象知识分析实际问题、解决实际问题的能力,提高学生的应用能力。...

    JAVA课程设计扑克游戏.doc

    使学生通过该 教学环节与手段,把所学课程及相关知识加以融会贯通,全面掌握Java语言的编程思想 及面向对象程序设计的方法,为今后从事实际工作打下坚实的基础。 本设计使用JAVA语言开发扑克游戏程序,将电脑多次...

    java网络编程技术课程设计.doc

    2 基础理论和技术 2.1网络基础知识 网络上的计算机要互相通信,必须遵循一定的协议。目前使用最广泛的网络协议是I nternet上所使用的TCP/IP协议。 在TCP/IP协议中IP层主要负责网络主机的定位,数据传输的路由,由IP...

Global site tag (gtag.js) - Google Analytics