最近一个网友问我,在面试阿里的时候,被问到了一个 String 字符串占用多少内存的问题?他当时懵了,因为他只记得基本数据类型占用的空间大小。

android string占用字节数 string所占字节_string去掉最后一个字符

说实话,这个问题,如果是我,我也可以会回答错误。

网上曾经有一道非常著名的题,如下:

android string占用字节数 string所占字节_java_02

既然选项是字节,那我们就应该这么算。



String str = "搞java"; 
 
   
  
System.out.println("\"搞java\".length():" + (str.length())); 
 
   
  
System.out.println("\"搞java\".getBytes().length:" + (str.getBytes().length)); 
 
   
  
System.out.println("\"搞java\".getBytes(\"GBK\").length:" + (str.getBytes("GBK").length)); 
 
   
  
System.out.println("\"搞java\".getBytes(\"UTF-8\").length:" + (str.getBytes("UTF-8").length)); 
 
   
  
/**
 
   
  
"搞java".length():5
 
   
  
"搞java".getBytes().length:6
 
   
  
"搞java".getBytes("GBK").length:6
 
   
  
"搞java".getBytes("UTF-8").length:7
 
   
  
*/




所以,选 A 或选 B 都说得过去。但是这是一个单选题,官方给出的最终正确答案是 A,即 6 个字节。原因是,我们的 Window 系统,默认的是 GBK,所以,答案为 A。

现在我们回归到的主题,一个 String 字符串占多少内存?就如上面这个选择题一样,看起来比 long 和 double 都要节约空间?

搜寻了好久,国外网友给出了一个计算公式:

android string占用字节数 string所占字节_System_03

这个公式看的我糊里糊涂的,我们看看 String 的源码。里面有一个 int 的 hash,还有一个 char [] 数组。所以,单纯的讲上面的字符串占用的空间肯定不止 6 个字节。

android string占用字节数 string所占字节_System_04

根据上面这个图,我们可以看出 String 对象的一个基本内存布局情况。需要注意的是 JDK 6 和 JDK 8 String 对象有所改动,计算方式不一样。

由上图可知,一个空 String 所占空间为:

对象头(8 字节)+ char 数组(16 字节)+ 3 个 int(3 × 4 = 12 字节)+1 个 char 数组的引用 (4 字节 ) = 40 字节。这里是 JDK 6 的计算方法。

JDK 8 中,只有一个 int 了,所以一个空的 String 占用 32 字节。

所以,我们最终可以总结一个公式:



// JDK 6
 
   
  
8*( ( 8+2*n+4+12)+7 ) / 8 = 8*(int) ( ( ( (n) *2 )+43) /8 )
 
   
  
// JDK 8
 
   
  
8*( ( 8+2*n+4+4)+7 ) / 8 = 8*(int) ( ( ( (n) *2 )+43) /8 )



其中 N 为字符串长度。

那个这个题,该怎么回答呢?说出你的思路,你对 String 内部结构的构成理解,和计算方式就可以了。实在记不住,也可以使用 Java 自带的 jol-core 工具来计算。



 org.openjdk.jol
 
   
  
 jol-core
 
   
  
 0.9
 
   
  
引入上面的 pom 配置,然后编写简单的几行代码就可以计算出来。
 
   
  
public class XttblogObjectMemory {
 
   
  
 public static void main(String[] args) {
 
   
  
 System.out.print(ClassLayout.parseClass(String.class)
 
   
  
 .toPrintable());
 
   
  
 }
 
   
  
}




空字符串的内存占用情况,计算结果如下所示:



java.lang.String object internals:
 
   
  
     OFFSET  SIZE     TYPE DESCRIPTION                   VALUE     
 
   
  
     0     12          (object header)                  N/A     
 
   
  
     12     4   char[] String.value                      N/A     
 
   
  
     16     4      int String.hash                       N/A
 
   
  
     20     4          (loss due to the next object alignment)
 
   
  
Instance size: 24 bytes


其他 Java 类的内存占用情况,也可以通过 jol-core 工具统计出来,用法和上面的类似。

以上,你知道的越多,不知道的就越多,业余的像一棵小草一样。