阿里面试官:字符串在JVM中如何存放?90%的人就真的只回答在哪里存放

Posted 石杉的架构笔记

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了阿里面试官:字符串在JVM中如何存放?90%的人就真的只回答在哪里存放相关的知识,希望对你有一定的参考价值。

每日早8点半,技术文章准时送上


往期文章

阿里面试官:字符串在JVM中如何存放?90%的人就真的只回答在哪里存放

本文来源:javaadu


目录:

  1. 一道面试题的引出

  2. 案例分析

  3. intern 源码分析

  4. 总结


1. 一道面试题的引出

在面试BAT这种一线大厂时,如果面试官问道:字符串在 JVM 中如何存放?大多数人能顺利的给出如下答案:


字符串对象在JVM中可能有两个存放的位置:字符串常量池或堆内存。


  • 使用常量字符串初始化的字符串对象,它的值存放在字符串常量池中;

  • 使用字符串构造方法创建的字符串对象,它的值存放在堆内存中;


但是如果能针对上述回答,做进一步扩展,会给你的面试表现加分不少,让你从一大波候选人中脱颖而出。下面就一起来分析一下。


首先来看,String提供了一个API, java.lang.String.intern(),这个API可以手动将一个字符串对象的值转移到字符串常量池中


在1.7之前,字符串常量池是在PermGen区域,这个区域的大小是固定的,不能在运行时根据需要扩大,也不能被垃圾收集器回收,因此如果程序中有太多的字符串调用了intern方法的话,就可能造成OOM。


在1.7以后,字符串常量池移到了堆内存中,并且可以被垃圾收集器回收,这个改动降低了字符串常量池OOM的风险。


2. 案例分析

阿里面试官:字符串在JVM中如何存放?90%的人就真的只回答在哪里存放

验证代码:

 
   
   
 
  1. public class StringTest {


  2. public static void main(String[] args) {

  3. String s1 = "javaadu";

  4. String s2 = "javaadu";

  5. String s3 = new String("javaadu");

  6. System.out.println(s1 == s2); //true

  7. System.out.println(s1 == s3); //false


  8. String s4 = s3.intern();

  9. System.out.println(s1 == s4); //true

  10. }

  11. }


3. intern源码分析

我们来看intern方法的实现,intern方法的底层是一个native方法,在Hotspot JVM里字符串常量池它的逻辑在注释里写得很清楚:


如果常量池中有这个字符串常量,就直接返回,否则将该字符串对象的值存入常量池,再返回。

阿里面试官:字符串在JVM中如何存放?90%的人就真的只回答在哪里存放

这里以Openjdk1.8的源码为例,跟下intern方法的底层实现,String.java文件对应的C文件是String.c:

 
   
   
 
  1. JNIEXPORT jobject JNICALL

  2. Java_java_lang_String_intern(JNIEnv *env, jobject this)

  3. {

  4. return JVM_InternString(env, this);

  5. }

JVM_InternString这个方法的定义在jvm.h,实现在jvm.cpp中,在JVM中,Java世界和C++世界的连接层就是jvm.h和jvm.cpp这两文件。

 
   
   
 
  1. JVM_ENTRY(jstring, JVM_InternString(JNIEnv *env, jstring str))

  2. JVMWrapper("JVM_InternString");

  3. JvmtiVMObjectAllocEventCollector oam;

  4. if (str == NULL) return NULL;

  5. oop string = JNIHandles::resolve_non_null(str);

  6. oop result = StringTable::intern(string, CHECK_NULL);

  7. return (jstring) JNIHandles::make_local(env, result);

  8. JVM_END

可以看出,字符串常量池在JVM内部就是一个HashTable,也就是上面代码中的StringTable。

StringTable::intern方法跟下去,可以发现:如果找到了这次操作的字符串,就直接返回found_string;如果没有找到,就将当前的字符串加入到HashTable中,然后再返回。


4. 总结

在Java应用恰当得使用String.intern()方法有助于节省内存空间,但是在使用的时候,也需要注意,因为StringTable的大小是固定的,如果常量池中的字符串过多,会影响程序运行效率。

END


划至底部,点击“在看”,是你来过的仪式感!

阿里面试官:字符串在JVM中如何存放?90%的人就真的只回答在哪里存放



推荐阅读:









更多文章:

阿里面试官:字符串在JVM中如何存放?90%的人就真的只回答在哪里存放


BAT架构经验倾囊相授


以上是关于阿里面试官:字符串在JVM中如何存放?90%的人就真的只回答在哪里存放的主要内容,如果未能解决你的问题,请参考以下文章

阿里面试题:字符串对象在JVM中是如何存放的

教你如何预防Java面试90%的人都会踩得的坑~!

BTAJ大厂最新面试题汇集,90%的人看完都说好

史上最全!2020面试阿里,字节跳动90%被问到的JVM面试题(附答案)

史上最全!2020面试阿里,字节跳动90%被问到的JVM面试题(附答案)

90%的人会遇到性能问题,如何用1行代码快速定位?