博客
关于我
JVM系列之:String,数组和集合类的内存占用大小
阅读量:422 次
发布时间:2019-03-06

本文共 3820 字,大约阅读时间需要 12 分钟。

Java内存分析:String、数组与集合的结构解析

作为一名技术博主,我经常需要深入理解Java对象的内存布局,尤其是面对内存溢出(OOM)问题时,能够通过分析对象结构来找到问题根源。以下将从String、数组以及常见集合的内存布局入手,结合JOL工具的分析结果,带大家一探究竟。

数组的内存布局

首先,让我们从数组的内存布局说起。数组在Java中是非常基础的数据结构,它可以存储多个元素。通过JOL工具,我们可以深入分析一个数组对象的内存布局。

以下是使用JOL工具分析一个数组的输出结果:

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.

可以看到,数组对象的对象头大小为16字节,再加上数组里面的内容长度是15字节,再加上1位补全。最后得到的大小是32字节。这是因为数组的对象头占用了16字节,而数组本身存储的是基础类型的值,这些值在64位JVM中占用了15字节的空间。

需要注意的是,如果数组中存储的是对象类型(如引用),那么每个元素将占用4字节的空间。因此,在实际应用中,选择适当的数据类型对于内存管理至关重要。

String的内存布局

String类在Java中是特殊的,因为它底层是由byte数组实现的。这样看起来似乎有点奇怪,但实际上这是为了提高性能而做出的优化。以下是使用JOL工具分析一个String对象的输出结果:

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 bytesSpace losses: 0 bytes internal + 2 bytes external = 2 bytes total

从输出结果可以看出,String对象的对象头占用了12字节,接着是一个指向底层byte数组的4字节指针。再加上一些附加字段(如hash、coder和hasIsZero),最终String对象的大小为24字节。需要注意的是,这24字节不包括底层byte数组的大小,实际String的内存占用还包括底层数组的空间。

在JDK9之前,String的底层存储结构是char数组,而在JDK9之后,为了减少内存占用,底层存储结构改为byte数组。这种优化对于存储大量字符数据非常有用。

ArrayList的内存布局

ArrayList是Java中最常用的集合之一,它基于动态数组实现。以下是使用JOL工具分析一个ArrayList对象的输出结果:

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 bytesSpace losses: 0 bytes internal + 0 bytes external = 0 bytes total

从输出结果可以看出,ArrayList对象的对象头占用了8字节,接着是modCount和size字段,各占4字节。最后是一个指向底层Object数组的指针,占用4字节。整个ArrayList对象的大小为24字节。需要注意的是,底层数组的大小并不在 ArrayList对象的大小内存中占用,而是单独计算。

其他集合的内存布局

由于篇幅限制,我这里不会详细分析HashMap、HashSet、LinkedList和TreeMap等集合的内存布局。但可以简单提到,这些集合的内存布局通常包括对象头、数据存储区域以及一些管理字段(如计数器)。如果对这些集合的内存布局感兴趣,可以通过JOL工具自行进行分析。

总结

通过对String、数组和ArrayList等Java对象的内存布局分析,我们可以更好地理解它们在内存中的占用情况。选择合适的数据结构和集合类型,对于优化内存使用和解决内存溢出问题具有重要意义。

如果你对集合的内存布局感兴趣,可以继续阅读相关资料,深入探索这些集合在内存中的具体实现细节。希望本文能为你的Java内存分析之旅提供一些帮助!

转载地址:http://oiiuz.baihongyu.com/

你可能感兴趣的文章
poj 3422 Kaka's Matrix Travels (费用流 + 拆点)
查看>>
Qt笔记——官方文档全局定义(二)Functions函数
查看>>
POJ 3468 A Simple Problem with Integers
查看>>
poj 3468 A Simple Problem with Integers 降维线段树
查看>>
poj 3468 A Simple Problem with Integers(线段树 插线问线)
查看>>
poj 3485 区间选点
查看>>
poj 3518 Prime Gap
查看>>
poj 3539 Elevator——同余类bfs
查看>>
Qt笔记——官方文档全局定义(三)Macros宏
查看>>
poj 3628 Bookshelf 2
查看>>
Qt笔记——官方文档全局定义(一)Types数据类型
查看>>
POJ 3670 DP LIS?
查看>>
POJ 3683 Priest John's Busiest Day (算竞进阶习题)
查看>>
POJ 3988 Selecting courses
查看>>
POJ 4020 NEERC John's inversion 贪心+归并求逆序对
查看>>
poj 4044 Score Sequence(暴力)
查看>>
POJ 基础数据结构
查看>>
POJ 题目3020 Antenna Placement(二分图)
查看>>
Poj(1797) Dijkstra对松弛条件的变形
查看>>
SpringBoot为什么不需要xml配置文件?
查看>>