一个Java对象到底占多大内存?
最近在读《深入理解Java虚拟机》,对Java对象的内存布局有了进一步的认识,于是脑子里自然而然就有一个很普通的问题,就是一个Java对象到底占用多大内存?
在网上搜到了一篇博客讲的非常好:http://yueyemaitian.iteye.com/blog/2033046,里面提供的这个类也非常实用:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
|
import java.lang.instrument.Instrumentation;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.HashSet;
import java.util.Set;
/**
* 对象占用字节大小工具类
*
* @author tianmai.fh
* @date 2014-03-18 11:29
*/
public class SizeOfObject {
static Instrumentation inst;
public static void premain(String args, Instrumentation instP) {
inst = instP;
}
/**
* 直接计算当前对象占用空间大小,包括当前类及超类的基本类型实例字段大小、</br>
* 引用类型实例字段引用大小、实例基本类型数组总占用空间、实例引用类型数组引用本身占用空间大小;</br>
* 但是不包括超类继承下来的和当前类声明的实例引用字段的对象本身的大小、实例引用数组引用的对象本身的大小 </br>
*
* @param obj
* @return
*/
public static long sizeOf(Object obj) {
return inst.getObjectSize(obj);
}
/**
* 递归计算当前对象占用空间总大小,包括当前类和超类的实例字段大小以及实例字段引用对象大小
*
* @param objP
* @return
* @throws IllegalAccessException
*/
public static long fullSizeOf(Object objP) throws IllegalAccessException {
Set<Object> visited = new HashSet<Object>();
Deque<Object> toBeQueue = new ArrayDeque<Object>();
toBeQueue.add(objP);
long size = 0L;
while (toBeQueue.size() > 0 ) {
Object obj = toBeQueue.poll();
//sizeOf的时候已经计基本类型和引用的长度,包括数组
size += skipObject(visited, obj) ? 0L : sizeOf(obj);
Class<?> tmpObjClass = obj.getClass();
if (tmpObjClass.isArray()) {
//[I , [F 基本类型名字长度是2
if (tmpObjClass.getName().length() > 2 ) {
for ( int i = 0 , len = Array.getLength(obj); i < len; i++) {
Object tmp = Array.get(obj, i);
if (tmp != null ) {
//非基本类型需要深度遍历其对象
toBeQueue.add(Array.get(obj, i));
}
}
}
} else {
while (tmpObjClass != null ) {
Field[] fields = tmpObjClass.getDeclaredFields();
for (Field field : fields) {
if (Modifier.isStatic(field.getModifiers()) //静态不计
|| field.getType().isPrimitive()) { //基本类型不重复计
continue ;
}
field.setAccessible( true );
Object fieldValue = field.get(obj);
if (fieldValue == null ) {
continue ;
}
toBeQueue.add(fieldValue);
}
tmpObjClass = tmpObjClass.getSuperclass();
}
}
}
return size;
}
/**
* String.intern的对象不计;计算过的不计,也避免死循环
*
* @param visited
* @param obj
* @return
*/
static boolean skipObject(Set<Object> visited, Object obj) {
if (obj instanceof String && obj == ((String) obj).intern()) {
return true ;
}
return visited.contains(obj);
}
}
|
大家可以用这个代码边看边验证,注意的是,运行这个程序需要通过javaagent注入Instrumentation,具体可以看原博客。我今天主要是总结下手动计算Java对象占用字节数的基本规则,做为基本的技能必须get√,希望能帮到和我一样的Java菜鸟。
在介绍之前,简单回顾下,Java对象的内存布局:对象头(Header),实例数据(Instance Data)和对齐填充(Padding),详细的可以看我的读书笔记。另外:不同的环境结果可能有差异,我所在的环境是HotSpot虚拟机,64位Windwos。
下面进入正文:
对象头
对象头在32位系统上占用8bytes,64位系统上占用16bytes。
实例数据
原生类型(primitive type)的内存占用如下:
Primitive Type | Memory Required(bytes) |
boolean | 1 |
byte | 1 |
short | 2 |
char | 2 |
int | 4 |
float | 4 |
long | 8 |
double | 8 |
reference类型在32位系统上每个占用4bytes, 在64位系统上每个占用8bytes。
对齐填充
HotSpot的对齐方式为8字节对齐:
(对象头 + 实例数据 + padding) % 8等于0且0 <= padding < 8
指针压缩
对象占用的内存大小收到VM参数UseCompressedOops的影响。
1)对对象头的影响
开启(-XX:+UseCompressedOops)对象头大小为12bytes(64位机器)。
1
2
3
|
static class A {
int a;
}
|
A对象占用内存情况:
关闭指针压缩: 16+4=20不是8的倍数,所以+padding/4=24
开启指针压缩: 12+4=16已经是8的倍数了,不需要再padding。
2) 对reference类型的影响
64位机器上reference类型占用8个字节,开启指针压缩后占用4个字节。
1
2
3
4
|
static class B2 {
int b2a;
Integer b2b;
}
|
B2对象占用内存情况:
关闭指针压缩: 16+4+8=28不是8的倍数,所以+padding/4=32
开启指针压缩: 12+4+4=20不是8的倍数,所以+padding/4=24
数组对象
64位机器上,数组对象的对象头占用24个字节,启用压缩之后占用16个字节。之所以比普通对象占用内存多是因为需要额外的空间存储数组的长度。
先考虑下new Integer[0]占用的内存大小,长度为0,即是对象头的大小:
未开启压缩:24bytes
开启压缩后:16bytes
接着计算new Integer[1],new Integer[2],new Integer[3]和new Integer[4]就很容易了:
未开启压缩:
开启压缩:
拿new Integer[3]来具体解释下:
未开启压缩:24(对象头)+8*3=48,不需要padding;
开启压缩:16(对象头)+3*4=28,+padding/4=32,其他依次类推。
自定义类的数组也是一样的,比如:
1
2
3
4
|
static class B3 {
int a;
Integer b;
}
|
new B3[3]占用的内存大小:
未开启压缩:48
开启压缩后:32
复合对象
计算复合对象占用内存的大小其实就是运用上面几条规则,只是麻烦点。
1)对象本身的大小
直接计算当前对象占用空间大小,包括当前类及超类的基本类型实例字段大小、引用类型实例字段引用大小、实例基本类型数组总占用空间、实例引用类型数组引用本身占用空间大小; 但是不包括超类继承下来的和当前类声明的实例引用字段的对象本身的大小、实例引用数组引用的对象本身的大小。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
static class B {
int a;
int b;
}
static class C {
int ba;
B[] as = new B[ 3 ];
C() {
for ( int i = 0 ; i < as.length; i++) {
as[i] = new B();
}
}
}
|
未开启压缩:16(对象头)+4(ba)+8(as引用的大小)+padding/4=32
开启压缩:12+4+4+padding/4=24
2)当前对象占用的空间总大小
递归计算当前对象占用空间总大小,包括当前类和超类的实例字段大小以及实例字段引用对象大小。
递归计算复合对象占用的内存的时候需要注意的是:对齐填充是以每个对象为单位进行的,看下面这个图就很容易明白。
现在我们来手动计算下C对象占用的全部内存是多少,主要是三部分构成:C对象本身的大小+数组对象的大小+B对象的大小。
未开启压缩:
(16 + 4 + 8+4(padding)) + (24+ 8*3) +(16+8)*3 = 152bytes
开启压缩:
(12 + 4 + 4 +4(padding)) + (16 + 4*3 +4(数组对象padding)) + (12+8+4(B对象padding))*3= 128bytes
大家有兴趣的可以试试。
实际工作中真正需要手动计算对象大小的场景应该很少,但是个人觉得做为基础知识每个Java开发人员都应该了解,另外:对自己写的代码大概占用多少内存,内存中是怎么布局的应该有一个直觉性的认识。
一个Java对象到底占多大内存?相关推荐
- 一个Java对象到底占多大内存?(转)
最近在读<深入理解Java虚拟机>,对Java对象的内存布局有了进一步的认识,于是脑子里自然而然就有一个很普通的问题,就是一个Java对象到底占用多大内存? 在网上搜到了一篇博客讲的非常好 ...
- 一个Java对象到底占用多大内存?
最近在调研MAT和VisualVM源码实现,遇到一个可疑问题,两者计算出来的对象大小不一致,才有了这样疑惑. 一个Java对象到底占用多大内存? 为了复现这个问题,准备了4个最简单类: class A ...
- 一个Java对象到底有多大?
点击上方"方志朋",选择"置顶公众号" 技术文章第一时间送达! 出处:http://u6.gg/swLPg 编写Java代码的时候,大多数情况下,我们很少关注一 ...
- 一个 Java 对象到底有多大?
点击上方蓝色"程序猿DD",选择"设为星标" 回复"资源"获取独家整理的学习资料! 作者 | 李小武 来源 | http://blog.li ...
- java 如何循环执行一个对象_一个Java对象到底有多大?
编写Java代码的时候,大多数情况下,我们很少关注一个Java对象究竟有多大(占据多少内存),更多的是关注业务与逻辑.但是殊不知,在我们不经意间,大量的内存被无形地浪费了. 一个Java对象到底有多大 ...
- java有几大对象_一个 Java 对象到底有多大?
阅读本文大概需要 2.8 分钟. 出处:http://u6.gg/swLPg 编写 Java 代码的时候,大多数情况下,我们很少关注一个 Java 对象究竟有多大(占据多少内存),更多的是关注业务与逻 ...
- java占用内存多大_[转帖]一个Java工具到底占用多大内存?
一个Java工具到底占用多大内存? https://www.jianshu.com/p/194b745884a5 最近在调研MAT和VisualVM源码实现,遇到一个可疑问题,两者盘算出来的工具巨细不 ...
- java工具多,[转帖]一个 Java 工具到底有多大?
一个 Java 工具到底有多大? https://www.jianshu.com/p/5ad8b16a8f94 出处:http://u6.gg/swLPg 编写 Java 代码的时刻,大多数情况下,我 ...
- C++类对象到底占多大存储空间呢
目录 1. 空类占用1个字节的存储空间 2.类的成员函数(非虚函数)不占用类的存储空间 3.类的静态成员变量不占用类的存储空间 4.类中的虚函数占用类的存储空间,但所占的空间不会随着虚函数的个数增长 ...
- 一个Java对象占用多大内存
这个问题一般会出现在稍微高端一点的 Java 面试环节.要求面试者不仅对 Java 基础知识熟悉,更重要的是要了解内存模型. Java 对象模型 HotSpot JVM 使用名为 oops (Or ...
最新文章
- swiper.js 多图片页面的懒加载lazyLoading
- IOSday05 UIScrollView使用
- 【zabbix】安装、配置agent,配置被监控端
- Intel官宣开发RISC-V处理器:明年首发7nm工艺
- 华为读取版本exe_关于esrv_svc.exe和SurSvc.exe疑似泄露用户信息的猜测
- 设置MyEclipse编码、补全快捷键、字体大小
- mysql 安装no key_No package mysql-server available错误解决(centos mysql安装教程)
- 狂团KtAdmin框架正式免费开源发布,助力独立版SAAS系统快速开发
- MATLAB多元线性拟合——03
- 微服务的设计模式,你用了几个
- Android 修改zxing二维码样式
- c语言less函数,less用法总结
- 新闻发布系统——主页面分页
- erp沙盘采购总监的心得_erp沙盘模拟实验采购总监个人总结
- 关于电脑系统重装 bootmgr is missing
- Sniffer的讨论
- 新兴技术在金融领域(反洗钱)的应用
- 移动通信网络规划:毫米波技术
- 票据打印, 银行账单打印, 标签印刷, 文档打印, 条码打印, 批量打印, 包装纸打印与设计,可变数据打印,数据库印刷,HMI报表打印,VC++源码库解决方案
- VUE—移动端手机号正则验证,不正确显示‘请输入正确手机号’,若正确跳转到发送验证码(图文详情)
热门文章
- PDF Expert mac使用教程:压缩pdf文件大小
- 使用和编辑Mac的特殊触摸板命令?你值得一看
- ICPC North Central NA Contest 2017 B - Pokemon Go Go
- 前端开发之功能封装大全
- 如何利用FL Studio进行听湿录干的声音录制
- 大数据时代,数据恢复技巧你会了吗?
- 第01期:salesforce开发环境的搭建
- Day01 - 打开Linux大门
- 前端性能优化的常用手段
- 《vSphere性能设计:性能密集场景下CPU、内存、存储及网络的最佳设计实践》一1.2.4 存储...