作者个人研发在高并发场景下提供了一个简单、稳定、可扩展的延迟消息队列框架,具有精准的定时任务和延迟队列处理功能。开源半年多以来,已成功为十几家中小企业提供精准定时调度解决方案,经受住了生产环境的考验。为了造福更多的童鞋,这里给出开源框架的地址:https://github.com/sunshinelyz/mykit-delay最近朋友进群的时候写的,老是问一个问题:StringJava中的类占用多少内存空间?很多小伙伴的回答真是让我哭笑不得。有的说不占空间,有的说1个字节,有的说2个字节,有的说3个字节,还有的说不知道是的,更哭笑不得的是,还有人说是2到31力量。如果是这样的话,服务器的内存空间是装不下一个字符串的!作为程序员,我们不能开这样的玩笑。今天,我们就来说说Java中一个String到底占多少内存空间!Java对象的结构首先,让我们看一下虚拟机中Java对象的结构。这里以HotSpot虚拟机为例。注:图片来源http://r6d.cn/wp7q从上图可以看出对象在内存中的结构主要包括以下几个部分:MarkWord(标记字段):MarkWord部分对象占用4个字节,其内容是一系列标志位,如轻量级锁的标志位、偏向锁标志位等。KlassPointer(Class对象指针):Class对象指针的大小也是4个字节,它指向的位置是对应Class对象的内存地址(它对应的元数据对象)Objectactualdata:这包括对象的所有成员变量的大小由每个成员变量的大小决定,例如:byte和boolean是1个字节,short和char是2个字节,int和float是4个字节,long和double是8个字节,reference是4个-bytealignment:最后一部分是alignmentpadding的字节,用8个字节填充。也就是说:对象头:8字节(在虚拟机中保存对象的类信息、ID、状态)Java原始类型数据:如int、float、char等类型的数据引用(reference):4字节的padding(padding)Java中String类型的空String占用的空间这里我们以Java8为例进行说明。首先我们来看一下String类中的成员变量。/**该值用于字符存储。*/privatefinalcharvalue[];/**缓存字符串的哈希码*/privateinthash;//默认为0/**使用JDK1.0.2的serialVersionUID进行互操作*/privatestaticfinallongserialVersionUID=-6849794470754667710L;在Java中,数组也是对象。所以一个数组占用的空间就是对象头占用的空间加上数组的长度加上数组的引用,即8+4+4=16字节。因此,我们可以得到一个空String对象占用的内存空间,如下所示。对象头(8字节)+引用(4字节)+char数组(16字节)+1int(4字节)+1long(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,如下图。packageio.mykit.binghe.string.test;importjava.util.UUID;/***@authorbinghe*@version1.0.0*@description生成没有-*/publicclassUUIDUtils{publicstaticStringgetUUID(){Stringuuid=UUID.randomUUID()的UUID。toString();returnuuid.replace("-","");}}接下来创建一个TestString类,在main()方法中创建一个长度为4000000的数组,然后用UUID字符串填充数组,如如下。packageio.mykit.binghe.string.test;importjava.util.UUID;/***@authorbinghe*@version1.0.0*@description测试String占用的内存空间*/publicclassTestString{publicstaticvoidmain(String[]args){String[]strContainer=newString[4000000];for(inti=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内存分析工具得到的结果是符合我们预期的。本文转载自微信公众号“冰河科技”,可通过以下二维码关注。转载本文请联系冰川科技公众号。
