32Java GC面试题及答案(1~5题)_第1页
32Java GC面试题及答案(1~5题)_第2页
32Java GC面试题及答案(1~5题)_第3页
32Java GC面试题及答案(1~5题)_第4页
32Java GC面试题及答案(1~5题)_第5页
全文预览已结束

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、Java GC面试题及答案(15题)L既然有GC机制,为什么还会有内存泄露的情况?理论上Java因为有垃圾回收机制(GC)不会存在内存泄露问题(这也是Java被广泛使用于服务器端编程的一个圭要原因).然而在实 际开发中,可能会存在无用但可达的对象,这些对象不能被GC回收,因此也会导致内存泄露的发生.例如hibernate的Session (一级缓存)中的对象属于持久态,垃圾回收器是不会回收这些对象的,然而这些对象中可能存在无用的 垃圾对象,如果不及时关闭(close )或清空(flush ) 一级缓存就可能魏内存泄露.下面例子中的代码也会导致内存泄露.jeiva ut.il .Arrays;

2、javei , util , EmptyStackExceptiion;MySlackT elements;size = 0;工NIT CAPACITY -elements - (T) Object1N1T CAPACITY;push(T elcm) push(T elcm) push(T elcm) push(T elcm) elements sizg+ + J = eleni;(size = 0)(size = 0)(size = 0)EmptyStackException();(size = 0)EmptyStackException();elements-sizg;onsureCapa

3、cily () (elements. len- elements - Arrays.copyOf (elements,2 size !);上面的代码实现了一个栈(先进后出(FILO )结构,乍看之下似乎没有什么明显的问题,它甚至可以通过你编写的各种单元测试.然 而其中的pop方法却存在内存泄露的问题,当我们用pop方法弹出栈中的对象时,该对象不会被当作垃圾回收,即使使用栈的程序不再 引用这些对象,因为栈内部维护着对这些对象的过期引用(obsolete reference )。在支持垃圾回收的语言中,内存泄露是很隐蔽的, 这种内存泄露其实就是无意识的对象保持.如果一个对象引用被无意识的保存起来了

4、,那么垃圾回收器不会处理这个对段,也不会处理 该对象引用的X他对象,即使这样的对象只有少数几个,也可能会导致很多的对象被排除在垃圾回收之外,从而对性能造成更大影响, 极端情况下会引发Disk Paging (物理内存与硬盘的虚拟内存交换数据),甚至造成。utOfMemoryError.2、Java中为什么会有GC机制呢?安全性考虑;-for security.减少内存泄露;-erase memory leak in some degree.减少程序员工作IL -Programmers dont worry about memory releasing.3、对于Java的GC哪些内存需要回收?内

5、存运行时JVM会有一个运行时数据区来管理内存.它主要包括5大局部:.程序计数器(Program CounterRegister);.虚拟机筏(VM Stack);.本地方法栈(Native Method Stack);.方法区(Method Area);5.堆(Heap).而其中程序计数器、虚拟机栈、本地方法栈是每个线程私有的内存空间,随线程而生,随线程而亡.例如栈中每一个栈帧中分配多少内 存基本上在类结构确定是哪个时就了,因此这3个区域的内存分配和回收都是确定的,无需考虑内存回收的问题.但方法区和堆就不同了,一个接口的多个实现类需要的内存可能不一样,我们只有在程序运行期间才会知道会创立哪些对

6、象,这局部内 存的分配和回收都是动态的,GC主要关注的是这局部内存.总而言之,GC主要进行回收的内存是JVM中的方法区和堆.4、Java的GC什么时候回收垃圾?在面试中经常会碰到这样一个问题(事实上笔者也碰到过):如何判断一个对象已经死去?很容易想到的一个答案是:对一个对象添加引用计数器,每当有地方引用它时,计数器值加1 ;当引用失效时,计数器值减1.而当计数 器的值为0时这个对象就不会再被使用,判断为已死.是不是简单又直观。然而,很遗憾。这种做法是错误的!为什么是错的呢?事实 上,用引用计数法照实在大局部情况下是一个不错的解决方案,而在实际的应用中也有不少案例,但它却无法解决对象之间的循环引

7、用 问题。比方对象A中有一个字段指向了对象B ,而对象B中也有一个字段指向了对象A ,而事实上他们俩都不再使用,但计数器的值永 远都不可能为0 ,也就不会被回收,然后就发生了内存泄露.正确的做法应该是怎样呢?在Java , C#等语言中,比拟主流的判定f 对象已死的方法是:可达性分析(Reachability Analysis).所有生成的对象都是一个称为.GC Roots”的根的子树.从GC Roots开始向下搜索,搜索所经过的路径称为引用鹿(Reference Chain),当一个对象到GC Roots没有任何 引用链可以到达时,就称这个对象是不可达的(不可引用的),也就是可以被GC回收了

8、.无论是引用计数器还是可达性分析,判定对蕊是否存活都与引用有关!那么,如何定义对象的引用呢?我们希望给出这样一类描述:当内存空间还够时,能够保存在内存中;如果进行了垃圾回收之后内存空间仍旧非常紧张,那么可以抛弃这 些对象.所以根据不同的需求,给出如下四种引用,根据引用类型的不同,GC回收时也会有不同的操作:强引用(Strong Reference):Object obj=new Object。;只要强引用还存在,GC永远不会回收掉被引用的对象.软引用(Soft Reference):描述一些还有用但非必需的对象.在系统将会发生内存溢出之前,会把这些对象列入回收范围进行二次回收 (即系统将会发生

9、内存溢出了,才会对他们进行回收)弱引用(Weak Reference):程度比软引用还要弱一些.这些对象只能生存到下次GC之前.当GC工作时,无论内存是否足够都会将其 回收(即只要进行GC ,就会对他们进行回收.)虚引用(Phantom Reference):一个对象是否存在虚引用,完全不会对其生存时间构成影响。关于方法区中需要回收的是一些废弃的常 信和无用的类.L废弃的常量的回收。这里看引用计数就可以了。没有对象引用该常量就可以放心的回收了.2.无用的类的回收.什么是无用的类呢?A.该类所有的实例都己2被回收.也就是Java堆中不存在该类的任何实例;B加载该类的ClassLoader已经被回

10、收;C该类对应的对象没有任何地方被引用,无法在任何地方通过反射访问该类的方法.总而言之:对于堆中的对象,主要用 可达性分析判断一个对象是否还存在引用,如果该对嵌没有任何引用就应该被回收.而根据我们实际对引用的不同需求,又分成了 4种 引用,每种引用的回收机制也是不同的.对于方法区中的常量和类,当一个常量没有任何对象引用它,它就可以被回收了。而对于类, 如果可以判定它为无用类,就可以被回收了.5、通过10个例如来初步认识Java8中的lambda表达式用lambda表达式实现Runnable/ Java 8 之前:Thread( Runnable () .startrincln( Bctore

11、Jhh8 too much ccdo for loo little lo do );) .startThread()-System,out.printlnhi Java8. Lambda expression rocks !”),start();输出:too much code , for too little to doLambda expression rocks!这个例子向我们展示了 Java 8 lambda表达式的语法.你可以使用lambda写出如下代码:statementtamsj expression params)例如,如果你的方法不对参数进行修改、至写,只是在控制台打印点东西

12、的话,那么可以这样写:statementHello Laabdii Expressions );如果你的方法接收两个参数,那么可以写成如下这样:even, odd) - even + od眼便提一句,通常都会把lambda表达式内部变后的名字起得短一些.这样能使代码更简短,放在同一行.所以,在上述代码中,变最 名选用a、B或者x、y会比even、0dd要好.使用Java 8 lambda衷达式进行事件处理如果你用过Swing API编程,你就会记得怎样写事件监听代码。这又是一个旧版本简单匿名类的经典用例,但现在可以不这样了。你可 以用lambda表达式写出更好的事件监听代码,如下所示:Butt

13、on show = JButton( Show ); show.addActionListener (ActionListener) dellonPeriormoc(ActlonEvenl e) System.out .println ( Event handling wiihout lambda expression is boringshow , addActionListenerStem,out .print In (Light, CamerH, Action !|ambda oxprossions Rocks);使用Java 8 lambda表达式进行事件处理使用lambda表达式对列

14、表进行迭代如果你使过几年Java ,你就知道针对集合类,最常见的操作就是进行迭代,并将业务逻辑应用于各个元素,例如处理订单、交易和事件 的列表.由于Java是命令式语言,Java 8之前的所有循环代码都是I顶序的,即可以对其元素进行并行化处理,如果你想做并行过谑,就 需要自己写代码,这并不是困容易.通过引入lambda表达式和默认方法,将做什么和怎么做的问题分开了 ,这意味着Java集合现在 知道怎样做迭代,并可以在API层面对集合元素进行并行处理.下面的例子里,我将介绍如何在使用lambda或不使用lambda表达式 的情况下迭代列表.你可以看到列表现在有了 forEach。方法,它可以迭代

15、所有对象,并将你的lambda代码应用在其中.|List features = Arrays .dsListLambdas Defaul l Mclhod , SlrcaiaAPI Date and Time API ); (String feature :features)stemout printin(feature);List features = Arrays .msList ( Laabdas , Defaull Molhod Stream API . Ddle and Time API );features,forEach(n - System.。口c.println(口);eal

16、ures forEach(System.out:printin)输出:Lambdas Default Method Stream APIDate and Time API列表循环的最后 f例子展示了如何在Java 8中使用方法引用(method reference ).你可以看到C + +里面的双目号.范围解析操作 符现在在Java 8中用来表示方法引用.使用lambda表达式和函数式接口 Predicate除了在语言层面支持函数式编程风格Java 8也添加了一个包,叫做java.utiLfunction.它包含了很多类,用来支持Java的函数式编程. 其中一个便是Predicate ,使用函

17、数式接口以及lambda表达式,可以向API方法添加逻辑,用更少的代 码支持更多的动态行为.下面是Java 8 Predicate的例子,展示了过谑集合数据的多种常用方法.Predicate接口非常适用于做过派.List 二anguages=Auays asList (JavzJ, Scala, C+, Haskell, Lisp);filter(Languages, (str)-str.startsWith( J );rintln( languages uhich ends wiih a );f ilr.ar (st r ( ,i );System, out .print In ( Print all languages :);filter(languages, (str)System.out .printIn ( Pi int no language : );filter(languages.System.out.println ( Prinl liingiuig。 whose lenglh grouter Ihun 4:);eSr (str)-str.length()I);filler(List names. Predicate condition)(condit

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论