String引发的提问,我差点跪了
面试官:下面代码执行结果是什么?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引发的提问,我差点跪了的更多相关文章
- PHP 中一个 False 引发的问题,差点让公司损失一百万
PHP 中一个 False 引发的问题,差点让公司损失一百万 一.场景描述 上周我一个在金融公司的同学,他在线上写一个 Bug,差点造成公司损失百万.幸好他及时发现了这个问题并修复了.这是一个由 PH ...
- String属于“假引用类型”,代码为证(一个String引发的血案...)
一直以为String是引用类型,今天写了个浅拷贝的测试,发现String有基本类型的特征. class A{ public int a = 555; } class User implements C ...
- 差点跪了!阿里3面真题:CAP和BASE理论了解么?可以结合实际案例说下不?
本文节选自我开源的 JavaGuide :https://github.com/Snailclimb/JavaGuide (Github标星92k+!一份涵盖大部分 Java 程序员所需要掌握的核心知 ...
- 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 ...
- Java 征途:行者的地图
前段时间应因缘梳理了下自己的 Java 知识体系, 成文一篇望能帮到即将走进或正在 Java 世界跋涉的程序员们. 第一张,基础图 大约在 2003 年我开始知道 Java 的(当时还在用 Delph ...
- [转]Java 征途:行者的地图
前段时间应因缘梳理了下自己的 Java 知识体系, 成文一篇望能帮到即将走进或正在 Java 世界跋涉的程序员们. 第一张,基础图 大约在 2003 年我开始知道 Java 的(当时还在用 Delph ...
- 论一次iOS面试
最近觉得现在所在公司平台用户量太少,自身技术已经到了一个瓶颈,是时候需要换一个用户量多的平台,好好研究下iOS的性能优化.内存优化等问题了. 所面试的公司由于一些默认的规定,就不多说了,大致是面了一个 ...
- Java 征途:行者的地图 (转)
http://www.cnblogs.com/mindwind/p/5251430.html Java 征途:行者的地图 前段时间应因缘梳理了下自己的 Java 知识体系, 成文一篇望能帮到即将走 ...
- 最佳新秀SSH十六Struts2它是如何工作的内部
前面说完了Spring.Hibernate,非常自然今天轮到struts了.struts的核心原理就是通过拦截器来处理client的请求,经过拦截器一系列的处理后,再交给Action.以下先看看str ...
随机推荐
- Centos6.5 忘记密码解决方法
问题 原因 : 太久没用centos了 忘记密码了 很尴尬 快照也没说明密码.... 1.重启 centos 在开机启动的时候快速按键盘上的“E”键 或者“ESC”键(如果做不到精准快速可以在启动 ...
- Go调用cpp类
CGO是C语言和Go语言之间的桥梁,所以GO是没有办法直接使用CPP的类的. 我们可以通过增加一族C语言函数接口作为CPP类和CGO之前的桥梁的,这样 就可以实现C和Go之间的互联. my_buffe ...
- [Hadoop]Hive-1.2.x安装配置+Mysql安装
HIve的元数据存储在mysql中,需要配置与MySQL建立连接,除了安装MySQL外还要安装连接的jar包:mysql-connector-java-5.1.47.tar.gz 安装环境:Cen ...
- __new__与__init__的区别和应用场景
创建实例的时候, 先运行的_new_方法, _new_创建对象 Student object(实例)返回给 _init_ 里面的第一个参数self class Student(object): def ...
- [考试反思]1025csp-s模拟测试87:生存
想起一句话 课上求生存,课下求发展 发展还好说,如何生存? 生存很困难... 没什么可抱怨的.有AK的.高分的也很多. 该说的在<Dust>里说完了,安静会吧. 这场rank43怎么追? ...
- NOIP模拟 2
大概就是考试的时候慌的一批,因为一道正解也没想出来,T1,T3只会暴搜,听见天皇在旁边的窃喜声本渣内心是崩溃的 会打暴搜的我先打了暴搜,大多数时间都用在第二题上,妄想自己能拿50多分- 最后半小时万念 ...
- 主席树学习笔记(静态区间第k大)
题目背景 这是个非常经典的主席树入门题——静态区间第K小 数据已经过加强,请使用主席树.同时请注意常数优化 题目描述 如题,给定N个整数构成的序列,将对于指定的闭区间查询其区间内的第K小值. 输入输出 ...
- cmake 编译安装mysql5.5.32
1.安装cmake 上传tar包 rz cmake-2.8.8.tar.gz 解压tar包,并进入解压后的文件夹 tar xf cmake-2.8.8.tar.gz cd cmake-2.8.8 编译 ...
- Mysql中,update语句引起的时间戳自动更新问题
前几天遇到一个奇怪的问题. 在Mysql数据库中有一张表,表中有一个字段是timestamp类型的.我在update别的字段时,这个timestamp字段的时间会自动更新为当前时间. 后来发现,是My ...
- 三、netcore跨平台之 Linux配置nginx负载均衡
前面两章讲了netcore在linux上部署以及配置nginx,并让nginx代理webapi. 这一章主要讲如何配置负载均衡,有些步骤在前两章讲的很详细了,所以这一章我就不会一个个截图了. 因为本人 ...