面试官:下面代码执行结果是什么?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. Java自动化测试框架-09 - TestNG之依赖注入篇 (详细教程)

    1.-依赖注入 TestNG支持两种不同类型的依赖项注入:本机(由TestNG本身执行)和外部(由诸如Guice的依赖项注入框架执行). 1.1-本机依赖项注入 TestNG允许您在方法中声明其他参数 ...

  2. linux shell 小技能

    环境: [root@test ~]# cat /etc/redhat-release CentOS release 6.5 (Final) [root@test ~]# uname -a Linux ...

  3. 学习笔记_58 python语法基础

    1.python是解析型语言. 有点像javaScript在html运行一样,不需要mian函数入口,随时随地定义函数,执行函数, 执行语句,定义类型 2.python能面向对象 3.python使用 ...

  4. 梯度下降法及一元线性回归的python实现

    梯度下降法及一元线性回归的python实现 一.梯度下降法形象解释 设想我们处在一座山的半山腰的位置,现在我们需要找到一条最快的下山路径,请问应该怎么走?根据生活经验,我们会用一种十分贪心的策略,即在 ...

  5. Java自动化测试框架-11 - TestNG之annotation与并发测试篇 (详细教程)

    1.简介 TestNG中用到的annotation的快速预览及其属性. 2.TestNG基本注解(注释) 注解 描述 @BeforeSuite 注解的方法只运行一次,在当前suite所有测试执行之前执 ...

  6. NOIP模拟赛 华容道 (搜索和最短路)蒟蒻的第一道紫题

    题目描述 小 B 最近迷上了华容道,可是他总是要花很长的时间才能完成一次.于是,他想到用编程来完成华容道:给定一种局面, 华容道是否根本就无法完成,如果能完成, 最少需要多少时间. 小 B 玩的华容道 ...

  7. [转载]2.1 UiPath条件判断活动If的介绍和使用

    一.if的介绍 if语句是指编程语言(包括c语言.C#.Python.Java.汇编语言等)中用来判定所给定的条件是否满足,根据判定的结果(真或假)决定执行给出的两种操作之一. 二.if在UiPath ...

  8. LINQ学习——Group

    一.Group的作用 1.Group字句把select的对象根据一些标准进行分组. 2.从查询表达式返回的对象是从查询中枚举分组结果的可枚举类型. 3.每一个分组由一个叫做键的字段区分. 4.每一个分 ...

  9. Elasticsearch系列---Elasticsearch的基本概念及工作原理

    基本概念 Elasticsearch有几个核心的概念,花几分钟时间了解一下,有助于后面章节的学习. NRT Near Realtime,近实时,有两个层面的含义,一是从写入一条数据到这条数据可以被搜索 ...

  10. PHP获取图片每个像素点

    PHP获取图片每个像素点<pre> $i = imagecreatefromjpeg("test.jpg"); //图片路径 for ($x = 0; $x < ...