面试官:下面代码执行结果是什么?String t0 = "helloworld";String t1 = new String("helloworld");System.out.println(t0==t1);
小白:(心里嘀咕:不会这么简单吧)false

面试官:详细解释一下为什么?
小白:在Java虚拟机栈中创建一个String类型变量t0,然后会优先在方法区的运行时常量池中查找是否已经存在相同的字符串,倘若已经存在,栈中t0变量直接指向该字符串;倘若不存在,则在常量池中创建一个"helloworld"字符串,再将栈中t0变量指向该字符串。通过new关键字创建字符串对象,首先当前类被加载后,会在方法区的运行时常量池中查找是否已经存在"helloworld"字符串,如果不存在,则将编译期生成的"helloworld"存到运行时常量池中,如果已存在不存放,在堆中生成一个String类型的对象,栈中t1变量指向该对象。因为t0和t1指向的对象不同,当使用==做比较时,比较的是对象的引用(可能是指向对象起始地址的引用指针,也可能是指向一个代表对象的句柄或其它与此对象相关的位置),自然返回的是false。

面试官:那下面代码的运行结果又是什么?String t0 = new String("hello") + new String("world");t0.intern();String t1 = "helloworld";System.out.println(t0 == t1);
小白:JDK1.7之前的版本为false,JDK1.7开始为true。

面试官:为什么结果不同?
小白:JDK1.7之前的版本中,intern方法会优先在方法区的运行时常量池中查找是否已经存在相同的字符串,倘若已经存在,则返回已存在的字符串,否则则在常量池中添加一个字符串常量,并返回字符串。从JDK1.7开始,HotSpot虚拟机将字符串常量移至Java Heap,intern方法的实现也发生了变化,首先还是会先去查询常量池中是否已经存在,如果存在,则返回常量池中的字符串,否则不再将字符串拷贝到常量池,而只是在常量池中保存字符串对象的引用。

面试官:介绍一下JVM运行时数据区中的Java虚拟机栈?
小白:Java虚拟机栈是线程私有的,每个线程有各自独立的Java虚拟机栈,它的生命周期跟随线程,线程启动时被创建,线程结束时被销毁。它用来存储Java方法运行时的数据,当执行一个Java方法时,都会创建一个对应的栈帧,栈帧里存储方法局部变量表、操作数栈、动态链接、方法出口信息等,这个过程称为入栈;当方法执行完成后,对应的栈帧会被销毁,这个过程称为出栈。

面试官:局部变量表、操作数栈、动态链接和方法出口信息分别如何理解?
小白:局部变量表主要存放方法参数和方法内部定义的局部变量,如果是基本数据类型,存储的是其变量的值,如果是引用类型,存储的是对象引用;操作数栈可以理解为正在操作中需要处理的数据和结果数据;每个栈帧都包含一个指向运行时常量池中该栈帧所属方法的引用,在方法调用过程中将符号引用转化为直接引用称为动态链接;方法出口信息记录了当前方法正常执行完成后,应该回到的上层调用者的位置信息,或者是方法执行异常退出时,应该回到的异常处理的位置信息。

面试官:局部变量表中存储了对象引用,如何通过这个引用找到对象?
小白:一般情况下对象是在堆中创建存储的,访问堆中的对象,可以通过句柄和直接指针两种方法。句柄方式:在Java堆中划分了一块区域叫句柄池,局部变量表中对象引用存储的是句柄的地址,通过这个地址到句柄池中找到句柄,句柄中存储了对象实例数据的地址和对象类型数据的地址,通过他们可以找到对象的实际数据和对象的类型信息。直接指针:局部变量表中对象引用存储的就是对象的地址,通过这个地址可以在堆中直接找到对象,同时在对象实例数据中还存储了对象类型的地址,通过这个地址可以在方法区中找到对应的对象类型信息,HotSpot虚拟机使用的就是这种方式。

面试官:说到引用,Java中引用有哪几种?分别是什么?
小白:Java中按引用的强度分为强引用、软引用、弱引用和虚引用四种。强引用,例如Object obj = new Object();这里的obj对Object实例对象的引用就是强引用。软引用,例如Object obj = new Object();SoftReference sf = new SoftReference(obj);这里sf是对obj的一个软引用,软引用引用的对象会在系统将要发生内存溢出之前,被列入垃圾回收的范围进入回收。弱引用,例如Object obj = new Object();WeakReference wf = new WeakReference(obj);这里wf是对obj的一个弱引用,当发生垃圾回收时,弱引用引用的对象将会被回收掉。虚引用,例如Object obj = new Object();PhantomReference pf = new PhantomReference(obj);这里pf是对obj的一个虚引用,虚引用关联的对象被回收时会收到系统通知,多用于跟踪垃圾回收过程。

面试官:ThreadLocal源码实现中使用到了弱引用,有了解过吗?
小白:ThreadLocal的实现原理是每一个Thread维护一个ThreadLocalMap映射表,映射表的key是ThreadLocal实例,并且使用的是ThreadLocal的弱引用 ,value是具体需要存储的Object。用一张图展示这些对象之间的引用关系,实心箭头表示强引用,空心箭头表示弱引用。

面试官:那ThreadLocal中弱引用导致的内存泄漏是如何发生的?
小白:如果ThreadLocal没有外部强引用,当发生垃圾回收时,这个ThreadLocal一定会被回收(弱引用的特点是不管当前内存空间足够与否,GC时都会被回收),这样就会导致ThreadLocalMap中出现key为null的Entry,外部将不能获取这些key为null的Entry的value,并且如果当前线程一直存活,那么就会存在一条强引用链:Thread Ref -> Thread -> ThreaLocalMap -> Entry -> value,导致value对应的Object一直无法被回收,产生内存泄露。

面试官:如何解决?
小白:查看源码会发现,ThreadLocal的get、set和remove方法都实现了对所有key为null的value的清除,但仍可能会发生内存泄露,因为可能使用了ThreadLocal的get或set方法后发生GC,此后不调用get、set或remove方法,为null的value就不会被清除。解决办法是每次使用完ThreadLocal都调用它的remove()方法清除数据,或者按照JDK建议将ThreadLocal变量定义成private static,这样就一直存在ThreadLocal的强引用,也就能保证任何时候都能通过ThreadLocal的弱引用访问到Entry的value值,进而清除掉。

留一个小问题,输出结果是true?false?
String t0 = "a";
String t1 = "b";
String t2 = t0 + t1;
String t3 = "ab";
System.out.println(t2==t3);

关注不迷路,记录后端开发那些事

String引发的提问,我差点跪了的更多相关文章

  1. PHP 中一个 False 引发的问题,差点让公司损失一百万

    PHP 中一个 False 引发的问题,差点让公司损失一百万 一.场景描述 上周我一个在金融公司的同学,他在线上写一个 Bug,差点造成公司损失百万.幸好他及时发现了这个问题并修复了.这是一个由 PH ...

  2. String属于“假引用类型”,代码为证(一个String引发的血案...)

    一直以为String是引用类型,今天写了个浅拷贝的测试,发现String有基本类型的特征. class A{ public int a = 555; } class User implements C ...

  3. 差点跪了!阿里3面真题:CAP和BASE理论了解么?可以结合实际案例说下不?

    本文节选自我开源的 JavaGuide :https://github.com/Snailclimb/JavaGuide (Github标星92k+!一份涵盖大部分 Java 程序员所需要掌握的核心知 ...

  4. The method replace(int, Fragment, String) in the type FragmentTransaction is not applicable for the arguments (int, SettingFragment, String)

    The method replace(int, Fragment, String) in the type FragmentTransaction is not applicable for the ...

  5. Java 征途:行者的地图

    前段时间应因缘梳理了下自己的 Java 知识体系, 成文一篇望能帮到即将走进或正在 Java 世界跋涉的程序员们. 第一张,基础图 大约在 2003 年我开始知道 Java 的(当时还在用 Delph ...

  6. [转]Java 征途:行者的地图

    前段时间应因缘梳理了下自己的 Java 知识体系, 成文一篇望能帮到即将走进或正在 Java 世界跋涉的程序员们. 第一张,基础图 大约在 2003 年我开始知道 Java 的(当时还在用 Delph ...

  7. 论一次iOS面试

    最近觉得现在所在公司平台用户量太少,自身技术已经到了一个瓶颈,是时候需要换一个用户量多的平台,好好研究下iOS的性能优化.内存优化等问题了. 所面试的公司由于一些默认的规定,就不多说了,大致是面了一个 ...

  8. Java 征途:行者的地图 (转)

    http://www.cnblogs.com/mindwind/p/5251430.html Java 征途:行者的地图   前段时间应因缘梳理了下自己的 Java 知识体系, 成文一篇望能帮到即将走 ...

  9. 最佳新秀SSH十六Struts2它是如何工作的内部

    前面说完了Spring.Hibernate,非常自然今天轮到struts了.struts的核心原理就是通过拦截器来处理client的请求,经过拦截器一系列的处理后,再交给Action.以下先看看str ...

随机推荐

  1. Dijkstra算法 笔记与思路整理

    该文章可能存在硬伤与不妥,不能作为教程阅读.(因为我真的鶸 Dij作为单源最短路算法,需要先确定一个起点.Dij的函数主体为维护每个节点的dis和vis两个变量.dis表示该点距离起点的最短路权值和, ...

  2. 学习笔记57_WCF基础

    参考书籍<WCF揭秘> 参考博客园“xfrog” 1.做一个接口,例如: 2.使用一个类,例如:FirstSrvice这个类,来实现这个接口. 3.建立WCF的  宿主   程序: 4.配 ...

  3. NOIP模拟测试7

    期望得分:60+60+60 实际得分:60+60+0 这次考试主要是T3搜索打挂了(我可是靠搜索吃饭的); 1.数组开小了,不过开大数组只拿到了10分的好成绩. 2.题意没审清(其实是他没说清). 以 ...

  4. 爬虫学习--Day4(网页采集器的实现)

    #UA: User-Agent {请求载体的身份标识}#(反爬机制)UA检测:门户网站的服务器回检测对应请求的载体身份标识,如果检测到请求的载体身份为某一款浏览器就说明该请求时一个正常的请求.但是,如 ...

  5. jquery 用creatjs preloadjs的方法

    jquery 用creatjs preloadjs的方法<pre><!DOCTYPE html><html lang="en"><head ...

  6. C# 操作本地用户和组(基本全功能)

    今天学习了下怎么用.Net操作本地用户和组,因为目前网上还没看到一篇比较完整的文章,所以整理了下也分享出来,最后附带参考文档,方便深究的童鞋继续学习.==========  原创作品    作者:Yo ...

  7. GitHub和Git

    GitHub托管项目代码 首先一些基本概念: repository(仓库) 用来存放项目代码,每个项目代表一个仓库,开一个项目就意味着你有一个仓库. star(收藏) 收藏方便下次查找. fork(复 ...

  8. PHP 教你使用 Swoole-Tracker 秒级定位 PHP 卡死问题

    PHPer 肯定收到过这样的投诉:小菊花一直在转!你们网站怎么这么卡!当我们线上业务遇到这种卡住(阻塞)的情况,大部分 PHPer 会两眼一抹黑,随后想起那句名言:性能瓶颈都在数据库然后把锅甩给DBA ...

  9. (C#)WPF:.h(头文件)、.lib(静态链接库文件)和.dll(动态链接库文件)之间的区别与联系

    静态链接库(Lib)与动态链接库(DLL)的区别 静态连接库就是把(lib)文件中用到的函数代码直接链接进目标程序,程序运行的时候不再需要其它的库文件:动态链接就是把调用的函数所在文件模块(DLL)和 ...

  10. 第一篇: openJDK源码编译安装--mac版本

    1.为什么要编译JDK 想要一探JDK内部的实现机制,最便捷的路径之一就是自己编译一套JDK,通过阅读和跟踪调试JDK源码去了解Java技术体系的原理,虽然门槛高一点,但肯定比阅读各种书籍,文章,博客 ...