作者个人研发的在高并发场景下,提供的简单、稳定、可扩展的延迟消息队列框架,具有精准的定时任务和延迟队列处理功能。自开源半年多以来,已成功为十几家中小型企业提供了精准定时调度方案,经受住了生产环境的考验。为使更多童鞋受益,现给出开源框架地址:https://github.com/sunshinelyz/mykit-delay
写在前面
最近小伙伴加群时,我总是问一个问题:Java中的String类占用多大的内存空间?很多小伙伴的回答着实让我哭笑不得,有说不占空间的,有说1个字节的,有说2个字节的,有说3个字节的,有说不知道的,更让人哭笑不得的是竟然还有人说是2的31次方。那如果真是这样的话,服务器的内存空间还放不下一个字符串呀!作为程序员的我们,可不能闹这种笑话呀。今天,我们就一起来聊聊Java中的String到底占用多大的内存空间!
Java对象的结构
首先,我们来下Java对象在虚拟机中的结构,这里,以HotSpot虚拟机为例。
注:图片来源http://r6d.cn/wp7q
从上面的这张图里面可以看出,对象在内存中的结构主要包含以下几个部分:
换种说法就是:
Java中的String类型
空String占用的空间
这里,我们以Java8为例进行说明。首先,我们来看看String类中的成员变量。
- /** The value is used for character storage. */
- private final char value[];
- /** Cache the hash code for the string */
- private int hash; // Default to 0
- /** use serialVersionUID from JDK 1.0.2 for interoperability */
- private static final long serialVersionUID = -6849794470754667710L;
在 Java 里数组也是对象,因此数组也有对象头。所以,一个数组所占的空间为对象头所占的空间加上数组长度加上数组的引用,即 8 + 4 + 4= 16 字节 。
所以,我们可以得出一个空String对象所占用的内存空间,如下所示。
- 对象头(8 字节)+ 引用 (4 字节 ) + char 数组(16 字节)+ 1个 int(4字节)+ 1个long(8字节)= 40 字节
所以,小伙伴们,你们的回答正确吗?
非空String占用的空间
如果String字符串的长度大于0的话,我们也可以得出String占用内存的计算公式,如下所示。
- 40 + 2 * n
其中,n为字符串的长度。
这里,可能有小伙伴会问,为什么是 40 + 2 * n 呢?这是因为40是空字符串占用的内存空间,这个我们上面已经说过了,String类实际上是把数据存储到char[]这个成员变量数组中的,而char[]数组中的一个char类型的数据占用2个字节的空间,所以,只是String中的数据就会占用 2 * n(n为字符串的长度)个字节的空间,再加上空字符串所占用的40个字节空间,最终得出一个字符串所占用的存储空间为:40 + 2 * n (n为字符串长度)。
因此在代码中大量使用String对象时,应考虑内存的实际占用情况。
注:40 + 2 * n 这个公式我们可以看成是计算String对象占用多大内存空间的通用公式。
验证结论
接下来,我们就一起来验证下我们上面的结论。首先,创建一个UUIDUtils类用来生成32位的UUID,如下所示。
- package io.mykit.binghe.string.test;
- import java.util.UUID;
- /**
- * @author binghe
- * @version 1.0.0
- * @description 生成没有-的UUID
- */
- public class UUIDUtils {
- public static String getUUID(){
- String uuid = UUID.randomUUID().toString();
- return uuid.replace("-", "");
- }
- }
接下来,创建一个TestString类,在main()方法中创建一个长度为4000000的数组,然后在数组中放满UUID字符串,如下所示。
- package io.mykit.binghe.string.test;
- import java.util.UUID;
- /**
- * @author binghe
- * @version 1.0.0
- * @description 测试String占用的内存空间
- */
- public class TestString{
- public static void main(String[] args){
- String[] strContainer = new String[4000000];
- for(int i = 0; i < 4000000; i++){
- strContainer[i] = UUIDUtils.getUUID();
- System.out.println(i);
- }
- //防止程序退出
- while(true){
- }
- }
- }
这里,4000000个字符串,每个字符串的长度为32,所以保存字符串数据所占用的内存空间为:(40 + 32 * 2) * 4000000 = 416000000字节,约等于416MB。
我们使用Jprofiler内存分析工具进行分析:
可以看到,使用Jprofiler内存分析工具的结果为:321MB + 96632KB,约等于417MB。之所以使用Jprofiler内存分析工具得出的结果比我们计算的大些,是因为在程序实际运行的过程中,程序内部也会生成一些字符串,这些字符串也会占用内存空间!!
所以,使用Jprofiler内存分析工具得出的结果符合我们的预期。
本文转载自微信公众号「冰河技术」,可以通过以下二维码关注。转载本文请联系冰河技术公众号。
本文中的五个步骤有助于您掌握转型的总体需求,并有助于您处理一些真正重要的事...
【51CTO.com快译】数字化转型使应用程序领导人必须找到有效的方法来更新改造遗留...
时间真快呀!转眼又至周一。让我们卯足干劲继续前行,先来看看上周有哪些不容错...
人头马君度(Rmy Cointreau)的历史非常重要,这家酒业公司以将最好的酒陈化100年...
在疫情的影响下,人们的工作和生活方式在过去的一年发生了前所未有的变化。为了...
根据调查,随着用户对计算能力、存储和网络容量的需求增长,服务器需求比经济不...
在VMworld 2020,VMware宣布与NVIDIA进行全面合作,共同推出新一代的混合云架构...
根据TrendForce的最新调查,自2020年初以来,COVID-19流感大流行加速了世界各地...
2020年11月26日深圳潮数科技于石家庄成功召开数据安全 新时代新基建信息应用之基...
2020年以来,由疫情停工减产所导致的缺芯困局影响着全球汽车发展,而本以为2021...