Java 中对象占用内存大小计算
原文地址 mp.weixin.qq.com
byte 与 bit
bit:位,比特。信息的最小单位,二进制数中的一个位数 (二进制位),其值为“0” 或“1”;
byte: 字节。计算机文件大小的基本计算单位;
原码:正数本身,负数,正数对应的二进制最高位为 1(负);
反码:正数本身,负数,符号位不变,其余各位取反;
补码:正数本身,负数:反码 + 1
0 的反码、补码都为零
注意: 计算机处理是以补码形式,我们最终看到的是原码形式
例如:
System.out.println((byte)233); // -23
System.out.println((byte)-233); // 23
System.out.println("~b2: " + ~10); // -11
列表
Java 基本类型
注意:
对于数组 32,默认为 int 型,32B 为 byte 类型,32S 为 short 类型,32L 为 long 型
基本数据类型自动转换 (低转高,高转低会丢失精度)
byte -> short
char -> int -> long
float -> double
int -> float
long -> double
后面会出一篇关于低转高,高转低的计算博文,敬请期待!
Java 中对象占用内存大小
对象的组成
可用如下一张图来概括
具体大小
名称 (单位 byte) | 32 位 | 64 位 | 开启指针压缩后 (指针对 64 位有效且默认开启) |
---|---|---|---|
对象头 (Header) | 8 | 16 | 12 |
数组对象头 | 12 | 24 | 16 |
引用 (reference) | 4 | 8 | 4 |
开启指针压缩指令
-XX:+UseCompressedOops
, 关闭指令-XX:-UseCompressedOops
, 只在 64 位才有效且默认开启;数组对象头比普通对象多了个数组长度;
对象头 (Header)
“用于存储对象自身的运行时数据,如哈希码(HashCode)、GC 分代年龄、锁状态标志、线程持有的锁、偏向线程 ID、偏向时间戳等,这部分数据的长度在 32 位和 64 位的虚拟机(未开启压缩指针)中分别为 32bit 和 64bit,官方称它为 "Mark Word”
实例数据 (Instance Data)
“对象真正存储的有效信息,也是在程序代码中所定义的各种类型的字段内容。无论是从父类继承下来的,还是在子类中定义的,都需要记录起来”
对其补充 (Padding)
“第三部分对齐填充并不是必然存在的,也没有特别的含义,它仅仅起着占位符的作用。由于 HotSpot VM 的自动内存管理系统要求对象起始地址必须是 8 字节的整数倍,换句话说,就是对象的大小必须是 8 字节的整数倍。而对象头部分正好是 8 字节的倍数(1 倍或者 2 倍),因此,当对象实例数据部分没有对齐时,就需要通过对齐填充来补全。”
HotSpot 的对齐方式为 8 字节对齐:
(Header + Instance Data + Paddding) % 8 = 0 并且 0 <= padding < 8
实战
Shallow
与 Retained
区别
再看具体的例子之前,需要了解下两个名词,下面使用 Java 性能监控工具Jprofile
会用到
Shallow Size
对象自身占用的内存大小,不包括它引用的对象针对非数组类型的对象,它的大小就是对象与它所有的成员变量大小的总和。当然这里面还会包括一些 java 语言特性的数据存储单元。
针对数组类型的对象,它的大小是数组元素对象的大小总和。
Retained Size
Retained Size = 当前对象大小 + 当前对象可直接或间接引用到的对象的大小总和。(间接引用的含义:A->B->C, C 就是间接引用)
注意:以下实验均在此环境下进行:
java version "1.8.0_171"
Java(TM) SE Runtime Environment (build 1.8.0_171-b11)
Java HotSpot(TM) 64-Bit Server VM (build 25.171-b11, mixed mode)
实例一:
publicclass A {privateint i;public static void main(String[] args) throws InterruptedException {A a = new A();Thread.sleep(1000 * 1000);System.out.println(a);}
}
分析: 64 位下默认开启指针压缩,对象头位 12byte, i
4byte, 此时 12 + 4 = 16 可以整除 8,所以 padding=0, 最终
12(header) + 4(instance data)+0(padding)=16byte
jprofile 结果如下:
如果我们关掉指针压缩,
16(header) + 4(instance data)+4(padding)=24byte
16+4=20, 不能整除 8,需要再加上 4,Jprofile
如下
实例二
publicclass B {privateint i = 5;private Integer ii = 128;public static void main(String[] args) throws InterruptedException {B b = new B();Thread.sleep(1000 * 1000);System.out.println(b);}
}
比较特殊的地方时这里复制了,因为包装类型有自己的缓存,可以看这里 *
开启指针压缩,计算内存大小
Shallow Size
:12(B Header) + 4 (i instance) + 4 (ii reference) + 4(padding) = 24bytes
Retained Size
: 12(B Header) + 4 (i instance) + 4 (ii reference) + (12(ii header) + 4(instance)+ 0(padding)) + 4(padding) = 40bytes
Jprofile
如下
实例三
publicclass C {privateint i;privatechar[] cc;public C() {i = 5;cc = newchar[]{'a', 'b', 'c'};}public static void main(String[] args) throws InterruptedException {C c = new C();Thread.sleep(1000 * 1000);System.out.println(c);}
}
多了数组,注意数组自己本身的 padding
Shallow Size
:12(C Header) + 4 (i instance) + 4 (cc reference) + 4(padding) = 24bytes
Retained Size
: 12(C Header) + 4 (i instance) + 4 (cc reference) + (16(cc header) + 2(instance) * 3+ 2(padding)) + 4(padding) = 48bytes
Jprofile
如下
实例四
publicclass D {private Map<String, String> map;public D() {map = new HashMap<>();map.put("A", "A");}public static void main(String[] args) throws InterruptedException {D d = new D();Thread.sleep(1000 * 1000);System.out.println(d);}
}
Shallow Size
: 12(D header) + 4(map reference) + 0(padding) = 16bytes
基本上Shallow Size
很容易就算出来
但是Retained Size
就异常的复杂,首先我们要去了解 HashMap 的结构
transient Node<K,V>[] table;
transient Set<Map.Entry<K,V>> entrySet;
transientint size;
transientint modCount;
int threshold;
finalfloat loadFactor// 来自AbstractMap
transient Set<K> keySet;
transient Collection<V> values;
Node 的结构如下:
finalint hash;
final K key;
V value;
Node<K,V> next;
注:此处的 K,V 是String
类型
再看String
的结构
/** The value is used for character storage. */privatefinalchar value[];/** Cache the hash code for the string */privateint hash; // Default to 0
以下是自己的计算过程,结果是对了,但不知道具体过程是否正确,仅供参考!!!
D 对象
12(D header) + 4(map reference)
=16HashMap:
12(header) + 4(table ref) + 4(entrySet ref) + 4(size) + 4(modCount) + 4(thresload) + 4(float) + 4(keySet ref) + 4(values ref) + 4(padding)=48
Node[]:
16(header) + 4(hash) + 4(key ref) + 4(val ref) + 4(next ref) + 0(padding)=32
K 与 V:
(12(hader) + 4(hash) + 4(value ref) + (16(value header) + 1 * 2(char)) + 2(padding) = 40) * 2=80
最终:16 + 48 + 32 + 80 = 176!!!
总结
最后总结一下,计算一个对象的大小需要注意一下几步:
Shallow 与 Retained 的区别;
对象本身的大小;
对象引用的对象也要注意对其补充,保证其也是被 8 整除的;
复杂对象需要深入分析
机器位数
能快速估算出每一个对象占用空间的大小可以在编程的时候正确选择数据结构,有兴趣的可以看一下这一节
“5.2.6 不恰当数据结构导致内存占用过大”
摘录来自: 周志明. “深入理解 Java 虚拟机:JVM 高级特性与最佳实践。” iBooks.
当然了,就算不知道怎么估算,最终还是有神器Jprofile
帮助我们监控性能与优化~
参考:
https://www.cnblogs.com/zhanjindong/p/3757767.html https://blog.csdn.net/ITer_ZC/article/details/41822719 https://segmentfault.com/a/1190000006933272 https://www.jianshu.com/p/40faea07d4d2
Java 中对象占用内存大小计算相关推荐
- Java 获取对象占用内存大小
1.第一步引入依赖 gradle引入:implementation group: 'org.apache.lucene', name: 'lucene-core', version: '4.0.0'i ...
- 安卓中图片占用内存大小分析
相关概念: 位深 色彩空间 颜色通道 int型占用字节 位深: 位是二进制的位.位深是指计算机系统中图片的一个像素点占用的二进制位数.例如位深32,就是使用2^8 = 32 位二进制来表示像素值.例如 ...
- Java 对象占用内存大小
Java 对象 如果想要了解java对象在内存中的大小,必须先要了解java对象的结构. HotSpot虚拟机中,对象在内存中存储的布局可以分为三块区域:对象头(Header).实例数据(Instan ...
- java对象占用内存大小?
一个不包含任何内部成员变量的空Object大约占33byte,若增加成员变量,则增加相应大小的内存占用. 测算方式:设置jvm的堆大小为1m,在堆中不停new不含任何成员变量的OOMObject对象, ...
- meo学习笔记4:C++中对象占用内存情况
C++中一个对象到底占用多少内存? 1.前言 这个问题对于开发可能不是那么的关注,但是其实在C++相关的题中却经常出现,下面将针对性的记录说明下这个问题 2.直蹦主题 2.1 重要结论 1)非静态成员 ...
- JVM对象占用内存计算
大家都知道,jvm中对象实例存储在堆中,对象的引用存储在栈中,而对象的元数据(类型数据)存储在方法区.在我们进行内存优化的过程中经常需要了解每个对象占用的内存大小.接下来我将介绍对象占用内存大小的计算 ...
- 2020 idea 查看内存消耗_查看运行时某个java对象占用JVM大小及通过idea查看java的内存占用情况...
一.如果想看运行时某个java对象占用JVM内存大小,可以先将对象转换成字节类型,然后计算: List bizGroupRelatedEventInfos = bizEventVersionMappe ...
- java String 最长长度和占用内存大小
一 序 String在内存中的最大长度理论上是int型变量的最大值,Integer.MAX_VALUE, String的字面常量的最大长度为CONSTANT_Utf8_info表决定,一般为65535 ...
- python获取对象的大小_Python实现计算对象的内存大小示例
本文实例讲述了Python实现计算对象的内存大小.分享给大家供大家参考,具体如下: 一般的sys.getsizeof()显示不了复杂的字典. 查看类中的内容: def dump(obj): for a ...
最新文章
- [SDOI2016]生成魔咒
- 在mac上搭建octopress+github pages博客
- 厉害了!Python+matplotlib制作8个排序算法的动画
- java 精通_你真的精通Java吗?
- 将JSON格式数据转换为javascript对象 JSON.parse()
- 原则,策略,规范也是构架的一部分
- 看libevent所遇到的英语生词
- 剑指offer:8-11记录
- leetcode41 --- firstMissingPositive
- 平时多流汗,战时少流血
- 蒙特卡洛模拟 matlab实例,蒙特卡洛模拟的简单例子
- 原生JS实现在线音乐播放器及歌词滚动
- 微信小程序的环境准备
- 记一次 Paramiko 提示 Authentication (publickey) failed问题解决过程
- html中如何设置动画效果,css3如何设置动画?
- Python算法- 剪绳子
- Schema being registered is incompatible with an earlier schema
- C语言 数组元素的遍历
- 第一章_Android入门
- 华三服务器操作系统兼容列表,FlexServer服务器操作系统兼容性列表.PDF