好厉害 http://blog.csdn.net/zq602316498/
2016-07-25 20:25
495 查看
很早就对数据在内存中的结构和体积有深入了解的想法。平时写代码的过程中,对于这些完全处于一种感性的认识,对于代码中使用的数据结构和对象,尤其是处理大量数据的时候,总有种把控不住的感觉。趁周六日有时间的功夫,通过查阅一些有关虚拟机和内存对象的资料,和Eclipse查看源码,自己琢磨着实实在在计算一下一个对象到底是占用了多少空间,它在内存中到底是个什么样子的。于是经过了两天的探索,总于有了下面这篇文章。
对于文章中涉及到的数据,不同的JDK环境可能会有一些小出入,这包括 JDK的版本,JDK32/64位,JVM参数分配的内存大小,垃圾回收器的种类。
就本文中的数据,来源于jdk1.7.0_79 64位,WIN7 64位,Eclipse Version: Mars Release (4.5.0)。
每个对象计算出的占用空间大小都是在自己机器上经过验证了的,具体的验证方法会在接来的一篇文章中贴出来。如果对文中的数据有疑问,十分欢迎指正交流,本着小菜鸟不断学习的态度,希望大家共同进步。
对象=对象头+成员变量+对齐填充
对象头结构:java对象在Heap里面的结构是这样的:对象头跟对象体,对象体跟C里面的结构体是一样的,对象头由两个域组成:用于存放hashcode、同步、GC的_mask域,和指向方法区该对象Class对象的指针——_klass域,对于64位系统,头部长度理论上讲应该是8+8=16字节。但是从java6u23以后开始,64位的机器会自动开启指针压缩的功能,此时引用指针的长度为4字节。所以,对象头长度应该为8+4=12。
成员变量:分两类,包括一些基本类型,如int,long.byte,short,boolean等,以及引用类型,如String,Date引用。如果是引用类型,也应该把引用类型指向的对象纳入当前对象。
对齐填充:JVM规定,对象的大小必须是8字节的整数倍,如果不足,则会补齐。
此外,对于数组,还会有一个标示数组长度的字段。其实数组也是一种类,会在后文中介绍。
以此为理论基础,我们来计算一下常用的对象占用空间大小。
Integer
类结构图:可以看到,只有一个私有的int型数据
所以Integer长度为:头(8+4)+ int(4) = 16字节
Long
类结构图
类似于Integer,只有一个long型的私有成员。
所以总长度为:头(8+4)+long(8)+padding(4)=24字节
Object
类结构图
没有成员变量,所以占用空间头(8+4)+padding(4)=16字节
String:“string”
类结构图
这个结构稍微有点复杂,涉及到了数组成员。其实数组也是一种类型,只不过这种类型是JVM在运行时生成的类型,并不在class文件中定义,我们将其当做一种特殊的类就可以了。既然涉及到了成员变量是对象,那么,我们就要把String分成两部分来计算:
String类型:头部(8+4)+int(4)+int(4)+指向char[]对象的引用类型(4)=24字节
char[]类型:数组类型比普通对象多一个标示数组长度的字段,占4个字节。对于字符串“String”来说,头部(8+4)+数组长度(4)+“String”(2*6)+padding(4)=32字节
因此,它的总占用空间为56字节
ArrayList
类结构图
其实,还有一个 modCount成员,继承自AbstractList类,那么对于一个 list = new ArrayList<String>(); list.add("String");的list来说,它拥有两个int,一个大小为10的数组(当 list.add() 第一个元素的时候,它会初始化elementData为一个长度10的数组)
ArrayList: 头部(8+4)+int(4)+int(4)+数组引用(4)=24字节
elementData[] : 头部(8+4)+长度(4)+string引用(4*10)=56字节
"String"字符串:这个我们之前计算过了,为56字节
所以,总空间大小为24+56+56=136字节
HashMap
类结构图
HashMap内部结构比较复杂,除了一些基本的类型,还有比较复杂一点的集合类型。如table,是一个Entry数组,用来存放键值对,所有put进map中key-value都会被封装成一个entry放入到table中去。而还有一些辅助对象,如entry,继承自AbstractMap的keySet,values,这些都是在遍历map元素时用到的集合,他们的主要功能是通过在自己内部维护一个迭代器向外输出table中的数据,并不实际储存key-value数据。
以 Map<String,String> map = new HashMap<String,String>(); 这时候我们计算一下他的占用空间情况:
总空间为:48+16=64字节
hashmap:头部(8)+int(4*4)+float(4)+table数组引用(4)+entrySet引用(4)+keySet引用(4)+values引用(4)+padding(4)=48字节
table:头部(8+4)+长度(4)=16字节
然后我们put进去一条数据:map.put( "100002", "张明");
当HashMap初始化的时候,他会开辟一个长度为16的table数组,每当put一个新的key-value的时候,他会根据当前threshold来判断是否需要扩容,如果需要扩容,则会以倍数增长的方式扩容table数组。如16、32、64.具体原理请参考 http://blog.csdn.net/zq602316498/article/details/39351363
接下来让我们计算一下这个map多占用的空间
hashmap:头部(8)+int(4*4)+float(4)+table数组引用(4)+entrySet引用(4)+keySet引用(4)+values引用(4)+padding(4)=48字节
table: 80+32+16+16+56+48+0= 216字节
table:头部(8+4)+长度(4)+entry(4*16)=80字节
entry:头部(8+4)+k(4)+value(4)+next(4)+int(4)+padding(4)=32字节
key(String):56字节
value(String) :48字节
next :因为就只有一个元素,所以next值为null,0字节
entrySet:为空指针,0字节
keySet:空指针,0字节
values:空指针,0字节
综上分析,这个map占用48+216+0+0+0=264字节
然后我们继续调用 map.keySet() 方法,此时,keySet会被赋予一个类型为 HashMap$KeySet 的对象,这个对象的结构如下:
可以看到,它并不复杂,只是用来遍历map key集合的一个工具类,
keySet : 头部(8+4)+padding(4)=16字节
所以,总大小为264+16=280字节
然后我们继续调动 map.values(),和上面类似
values : 头部(8+4)+padding(4)=16字节
所以,总大小为 280+16=296字节
然后我们继续调用 map.entrySet(),
entrySet:头部(8+4)+padding(4)=16字节
所以总大小为 296+16=312字节
如需转载,请注明原文地址:http://blog.csdn.net/zq602316498/
对于文章中涉及到的数据,不同的JDK环境可能会有一些小出入,这包括 JDK的版本,JDK32/64位,JVM参数分配的内存大小,垃圾回收器的种类。
就本文中的数据,来源于jdk1.7.0_79 64位,WIN7 64位,Eclipse Version: Mars Release (4.5.0)。
每个对象计算出的占用空间大小都是在自己机器上经过验证了的,具体的验证方法会在接来的一篇文章中贴出来。如果对文中的数据有疑问,十分欢迎指正交流,本着小菜鸟不断学习的态度,希望大家共同进步。
对象=对象头+成员变量+对齐填充
对象头结构:java对象在Heap里面的结构是这样的:对象头跟对象体,对象体跟C里面的结构体是一样的,对象头由两个域组成:用于存放hashcode、同步、GC的_mask域,和指向方法区该对象Class对象的指针——_klass域,对于64位系统,头部长度理论上讲应该是8+8=16字节。但是从java6u23以后开始,64位的机器会自动开启指针压缩的功能,此时引用指针的长度为4字节。所以,对象头长度应该为8+4=12。
成员变量:分两类,包括一些基本类型,如int,long.byte,short,boolean等,以及引用类型,如String,Date引用。如果是引用类型,也应该把引用类型指向的对象纳入当前对象。
对齐填充:JVM规定,对象的大小必须是8字节的整数倍,如果不足,则会补齐。
此外,对于数组,还会有一个标示数组长度的字段。其实数组也是一种类,会在后文中介绍。
以此为理论基础,我们来计算一下常用的对象占用空间大小。
Integer
类结构图:可以看到,只有一个私有的int型数据
所以Integer长度为:头(8+4)+ int(4) = 16字节
Long
类结构图
类似于Integer,只有一个long型的私有成员。
所以总长度为:头(8+4)+long(8)+padding(4)=24字节
Object
类结构图
没有成员变量,所以占用空间头(8+4)+padding(4)=16字节
String:“string”
类结构图
这个结构稍微有点复杂,涉及到了数组成员。其实数组也是一种类型,只不过这种类型是JVM在运行时生成的类型,并不在class文件中定义,我们将其当做一种特殊的类就可以了。既然涉及到了成员变量是对象,那么,我们就要把String分成两部分来计算:
String类型:头部(8+4)+int(4)+int(4)+指向char[]对象的引用类型(4)=24字节
char[]类型:数组类型比普通对象多一个标示数组长度的字段,占4个字节。对于字符串“String”来说,头部(8+4)+数组长度(4)+“String”(2*6)+padding(4)=32字节
因此,它的总占用空间为56字节
ArrayList
类结构图
其实,还有一个 modCount成员,继承自AbstractList类,那么对于一个 list = new ArrayList<String>(); list.add("String");的list来说,它拥有两个int,一个大小为10的数组(当 list.add() 第一个元素的时候,它会初始化elementData为一个长度10的数组)
ArrayList: 头部(8+4)+int(4)+int(4)+数组引用(4)=24字节
elementData[] : 头部(8+4)+长度(4)+string引用(4*10)=56字节
"String"字符串:这个我们之前计算过了,为56字节
所以,总空间大小为24+56+56=136字节
HashMap
类结构图
HashMap内部结构比较复杂,除了一些基本的类型,还有比较复杂一点的集合类型。如table,是一个Entry数组,用来存放键值对,所有put进map中key-value都会被封装成一个entry放入到table中去。而还有一些辅助对象,如entry,继承自AbstractMap的keySet,values,这些都是在遍历map元素时用到的集合,他们的主要功能是通过在自己内部维护一个迭代器向外输出table中的数据,并不实际储存key-value数据。
以 Map<String,String> map = new HashMap<String,String>(); 这时候我们计算一下他的占用空间情况:
总空间为:48+16=64字节
hashmap:头部(8)+int(4*4)+float(4)+table数组引用(4)+entrySet引用(4)+keySet引用(4)+values引用(4)+padding(4)=48字节
table:头部(8+4)+长度(4)=16字节
然后我们put进去一条数据:map.put( "100002", "张明");
当HashMap初始化的时候,他会开辟一个长度为16的table数组,每当put一个新的key-value的时候,他会根据当前threshold来判断是否需要扩容,如果需要扩容,则会以倍数增长的方式扩容table数组。如16、32、64.具体原理请参考 http://blog.csdn.net/zq602316498/article/details/39351363
接下来让我们计算一下这个map多占用的空间
hashmap:头部(8)+int(4*4)+float(4)+table数组引用(4)+entrySet引用(4)+keySet引用(4)+values引用(4)+padding(4)=48字节
table: 80+32+16+16+56+48+0= 216字节
table:头部(8+4)+长度(4)+entry(4*16)=80字节
entry:头部(8+4)+k(4)+value(4)+next(4)+int(4)+padding(4)=32字节
key(String):56字节
value(String) :48字节
next :因为就只有一个元素,所以next值为null,0字节
entrySet:为空指针,0字节
keySet:空指针,0字节
values:空指针,0字节
综上分析,这个map占用48+216+0+0+0=264字节
然后我们继续调用 map.keySet() 方法,此时,keySet会被赋予一个类型为 HashMap$KeySet 的对象,这个对象的结构如下:
可以看到,它并不复杂,只是用来遍历map key集合的一个工具类,
keySet : 头部(8+4)+padding(4)=16字节
所以,总大小为264+16=280字节
然后我们继续调动 map.values(),和上面类似
values : 头部(8+4)+padding(4)=16字节
所以,总大小为 280+16=296字节
然后我们继续调用 map.entrySet(),
entrySet:头部(8+4)+padding(4)=16字节
所以总大小为 296+16=312字节
如需转载,请注明原文地址:http://blog.csdn.net/zq602316498/
相关文章推荐
- 思科网络设备如何打出问号?字符
- Torch7学习(四)——学习神经网络包的用法(2)
- 网络编程的几个函数
- http缓存浅谈
- 基本控件使用(一)(遮罩、HTTP请求、ControlSlider、ControlSwitch、ProgressTo)
- 远程更新公告---目标软件-----枫彩网络工具箱
- 0143 [HLS]做自己的m3u8点播系统使用HTTP Live Streaming(HLS技术)
- 网络Http 相关 工具 类
- vagrant 网络
- HttpClient4.5和RestTemplate使用
- HTTP 介绍
- 跳转至系统网络设置界面
- CentOS tcpflow抓包
- java网络socket编程(六)之HTTP请求/响应报文
- 浅谈WebService SOAP、Restful、HTTP(post/get)请求
- 北京全时天地在线网络信息股份有限公司(投放广告)
- iOS网络请求工具oc版,swift版基于AFNetworking的简单封装
- Retrofit初探
- [置顶] Android之三种网络请求解析数据(最佳案例)
- javaWeb-----Http协议的解读