JVM系列之:String,数组和集合类的内存占用大小
简介
之前的文章中,我们使用JOL工具简单的分析过String,数组和集合类的内存占用情况,这里再做一次更详细的分析和介绍,希望大家后面再遇到OOM问题的时候不再抱头痛哭,而是可以有章可循,开始吧。
数组
先看下JOL的代码和输出:
//byte array
log.info("{}",ClassLayout.parseInstance("www.flydean.com".getBytes()).toPrintable());
输出结果:
INFO com.flydean.CollectionSize - [B object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 01 00 00 00 (00000001 00000000 00000000 00000000) (1)
4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
8 4 (object header) 22 13 07 00 (00100010 00010011 00000111 00000000) (463650)
12 4 (object header) 0f 00 00 00 (00001111 00000000 00000000 00000000) (15)
16 15 byte [B.<elements> N/A
31 1 (loss due to the next object alignment)
Instance size: 32 bytes
Space losses: 0 bytes internal + 1 bytes external = 1 bytes total
注意,本文的结论都在64位的JVM中运行得出了,并且开启了COOPs压缩对象指针技术。
可以看到数组对象的对象头大小是16字节,再加上数组里面的内容长度是15字节,再加上1位补全。最后得到的大小是32字节。
同样的,我们计算存有100个对象的数组,可以得到下面的结论:
注意最后面的Object数组,如果数组中存储的不是基础类型,那么实际上存储的是执行该对象的指针,该指针大小是4个字节。
String
String是一个非常特殊的对象,它的底层是以byte数组存储的。
注意,在JDK9之前,String的底层存储结构是char[],一个char需要占用两个字节的存储单位。
因为大部分的String都是以Latin-1字符编码来表示的,只需要一个字节存储就够了,两个字节完全是浪费。
于是在JDK9之后,字符串的底层存储变成了byte[]。
同样的我们还是用JOL来分析:
//String
log.info("{}",ClassLayout.parseInstance("www.flydean.com").toPrintable());
输出结果:
INFO com.flydean.CollectionSize - java.lang.String object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 05 00 00 00 (00000101 00000000 00000000 00000000) (5)
4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
8 4 (object header) 77 1a 06 00 (01110111 00011010 00000110 00000000) (399991)
12 4 byte[] String.value [119, 119, 119, 46, 102, 108, 121, 100, 101, 97, 110, 46, 99, 111, 109]
16 4 int String.hash 0
20 1 byte String.coder 0
21 1 boolean String.hashIsZero false
22 2 (loss due to the next object alignment)
Instance size: 24 bytes
Space losses: 0 bytes internal + 2 bytes external = 2 bytes total
可以看到String中的对象头是12字节,然后加上4字节的指针指向一个byte数组。再加上hash,coder,和hasIsZero属性,最后的大小是24字节。
我这里使用的是JDK14的String版本,不同的版本可能有所不同。
当然这只是这个String对象的大小,不包含底层数组的大小。
我们来计算一下String对象的真实大小:
String对象的大小+byte数组的大小=24+32=56字节。
ArrayList
我们构建一个非常简单的ArrayList:
//Array List
log.info("{}",ClassLayout.parseInstance(new ArrayList()).toPrintable());
输出结果:
INFO com.flydean.CollectionSize - java.util.ArrayList object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 05 00 00 00 (00000101 00000000 00000000 00000000) (5)
4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
8 4 (object header) 87 81 05 00 (10000111 10000001 00000101 00000000) (360839)
12 4 int AbstractList.modCount 0
16 4 int ArrayList.size 0
20 4 java.lang.Object[] ArrayList.elementData []
Instance size: 24 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total
画个图来直观的表示:
这里modCount和size的初始值都是0。
HashMap
因为文章篇幅的限制,这里就不把代码列出来了,我只贴个图上来:
HashSet
LinkedList
treeMap
来个比较复杂的TreeMap:
总结
本文用图形的形式形象的展示了集合对象,数组和String在内存中的使用情况。
后面的几个集合我就没有一一计算,有兴趣的朋友可以在下方回复你计算的结果哟。
本文作者:flydean程序那些事
本文链接:http://www.flydean.com/jvm-collections-size/
本文来源:flydean的博客
欢迎关注我的公众号:程序那些事,更多精彩等着您!
JVM系列之:String,数组和集合类的内存占用大小的更多相关文章
- JVM系列之:String.intern和stringTable
目录 简介 intern简介 intern和字符串字面量常量 分析intern返回的String对象 分析实际的问题 G1中的去重功能 总结 简介 StringTable是什么?它和String.in ...
- JVM系列之:String.intern的性能
目录 简介 String.intern和G1字符串去重的区别 String.intern的性能 举个例子 简介 String对象有个特殊的StringTable字符串常量池,为了减少Heap中生成的字 ...
- JVM系列(2)- jmap+mat实战内存溢出
熟悉几个监控JVM的常用命令 1. jps -l 查出当前服务器运行的java进程 --- 2. jinfo用法(结合jps -l查到进程ID) 1).查看最大堆内存:jinfo -flag MaxH ...
- JVM系列文章(三):Class文件内容解析
作为一个程序猿,只知道怎么用是远远不够的.起码,你须要知道为什么能够这么用.即我们所谓底层的东西. 那究竟什么是底层呢?我认为这不能一概而论.以我如今的知识水平而言:对于Web开发人员,TCP/IP. ...
- JVM系列第12讲:JVM参数之查看JVM参数
今天要说的是如何查看 JVM 中已经设置的参数,包括显示参数和隐式参数. 打印显式参数 -XX:+PrintVMOptions 该参数表示程序运行时,打印虚拟机接受到的命令行显式参数.我们用下面的命令 ...
- JVM内存占用情况深入分析
内存分布 首先,列举一下一个JVM进程主要占用内存的一些地方: Young Old metaspace java thread count * Xss other thread count * sta ...
- jvm系列 (五) ---类的加载机制
类的加载机制 目录 jvm系列(一):jvm内存区域与溢出 jvm系列(二):垃圾收集器与内存分配策略 jvm系列(三):锁的优化 jvm系列 (四) ---强.软.弱.虚引用 我的博客目录 什么是类 ...
- jvm系列 (五) ---类加载机制
类的加载机制 目录 jvm系列(一):jvm内存区域与溢出 jvm系列(二):垃圾收集器与内存分配策略 jvm系列(三):锁的优化 jvm系列 (四) ---强.软.弱.虚引用 我的博客目录 什么是类 ...
- jvm系列(1):JVM问答
一:JVM基础知识 1)Java 是如何实现跨平台的? 注意:跨平台的是 Java 程序,而不是 JVM.JVM 是用 C/C++ 开发的,是编译后的机器码,不能跨平台,不同平台下需要安装不同版本的 ...
随机推荐
- 客户端软件GUI开发技术漫谈:原生与跨平台解决方案分析
原生开发应用开发 Microsoft阵营的 Winform WinForm是·Net开发平台中对Windows Form的一种称谓. 如果你想深入的美化UI,需要耗费很大的力气,对于目前主流的CSS样 ...
- 谈谈我对C# 多态的理解
面向对象三要素:封装.继承.多态. 封装和继承,这两个比较好理解,但要理解多态的话,可就稍微有点难度了.今天,我们就来讲讲多态的理解. 我们应该经常会看到面试题目:请谈谈对多态的理解. 其实呢,多态非 ...
- SpringMVC 学习笔记(三)数据的校验
34. 尚硅谷_佟刚_SpringMVC_数据绑定流程分析.avi 例如:在jsp中输入一个String字符串类型,需要转换成Date类型的流程如下 convertservice对传入的数据进行转换 ...
- 恕我直言你可能真的不会java第7篇:像使用SQL一样排序集合
在开始之前,我先卖个关子提一个问题:我们现在有一个Employee员工类. @Data @AllArgsConstructor public class Employee { private Inte ...
- C语言资料分享
链接:https://pan.baidu.com/s/1hoc0sA0bDAq9XGC0pi2Kcg 提取码:60pn 复制这段内容后打开百度网盘手机App,操作更方便哦 c primer plus下 ...
- web页面的重构和回流【转载】
在了解什么是重构和回流之前,我们应该先看看浏览器是怎么渲染的? 浏览器的渲染过程: 1.处理HTML脚本,生成DOM树(DOM树里包含所有的HTML标签,包括display:none和js动态添加的元 ...
- C++中string转换为char*类型返回后乱码问题
问题来源: 在写二叉树序列化与反序列化时发现序列化函数为char* Serialize1(TreeNode *root) 其函数返回类型为char*,但是我在实现的过程中为了更方便的操作添加字符串使 ...
- 区间dp(能量项链)
[题目大意] 在Mars星球上,每个Mars人都随身佩带着一串能量项链.在项链上有N颗能量珠.能量珠是一颗有头标记与尾标记的珠子,这些标记对应着某个正整数.并且,对于相邻的两颗珠子,前一颗珠子的尾标记 ...
- MySQL CodeFirst的配置与注意事项
mysql+ef的配置相比较mssql+ef来说复杂一些.我的感受就是配置难度在于插件版本造成的各种不兼容问题.另外参考了很多博客,将多个博客里的经验综合才得以实现,因为不是每个人的操作都和那些博客作 ...
- Django---进阶6
目录 聚合查询 分组查询 F与Q查询 django中如何开启事务 orm中常用字段及参数 数据库查询优化 图书管理系统 作业 聚合查询 # 聚合查询 aggregate ""&qu ...