JVM面试

目录

①JVM如何判断一个对象可以被回收?

②能说一下JVM的内存区域吗?

③讲讲类加载机制?

④讲讲对象的创建过程?

⑤讲一讲JVM中的垃圾回收算法?

⑥讲一讲JVM的分代回收模型?

⑦讲一讲垃圾回收器?

⑧讲一讲堆和栈?

⑨TomCat为什么要打破双亲委派机制?以及如何打破双亲委派模型?

⑩JVM调优


①JVM如何判断一个对象可以被回收?

答:目前的话有两种方案。

第一种是叫引用计数器法来统计当前对象的引用次数,当对象被引用一次,计数器就会+1,当引用计数器为0时,意味着就可以被回收。这种方法实现简单效率高但是需要额外的空间。

第二种就是可达性分析算法,垃圾回收时JVM会Stop the World去找到所有的GC Root(虚拟机栈中的引用对象;方法区中类静态属性引用的对象;方法区中常量引用的对象;本地方法栈中引用的对象),然后向下搜索形成一条引用链,可达的对象保留下来,不可达的就会被回收。可达性分析算法现在是主流的算法。

Java中的几种引用,

强引用:通常通过new创建的对象就是强引用。引用还在就不可被回收。

软引用:相对于强引用弱一点的引用。只有当内存不足时才会去回收。

弱引用:不管内存是否充足,都会被GC回收掉。

虚引用:最弱的一种引用。必须配合队列使用,在对象被回收的时候会收到通知。

②能说一下JVM的内存区域吗?

答:JVM的内存区域粗略可以划分为线程私有和线程公有。按照虚拟机规范的话就会划分为方法区,虚拟机栈,堆,本地方法区,程序计数器。堆和方法区是线程公有的,其他的就是私有的。至于每一个区的作用,可以根据一个程序的运行来分析,首先类加载的时候把会把类的class文件的类信息,常量,静态变量等载入方法区,并且在堆中生成Class对象。然后运行到main函数,就会在虚拟机栈中添加一个栈帧,每个方法都有一个栈帧,栈帧可以放方法的局部变量等信息。之后如果方法中new一个对象,对象就是存在对堆中,像如果java还要调用本地方法就会存在本地方法栈中。最后程序计数器就是存储虚拟机指令要执行的下一条指令的地址。

③讲讲类加载机制?

答:首先类加载过程是:加载,链接(验证 准备 解析),初始化,当然后面还有使用和卸载。

首先加载过程是由类加载器完成的,类加载器又分为Bootstrap ClassLoader(启动类加载器)负责加载JRE的lib目录下的核心类库,Ext ClassLoader(扩展加载器)则是负责加载ext扩展目录下的类,Application ClassLoader(应用程序加载器)负责加载ClassPath路径下的类包和自定义加载器。加载的过程是在在加载前先访问上级加载器是否加载,直到访问到启动类加载器(不可见),这也叫做类加载的双亲委派机制。双亲委派作用:保证类的唯一性和安全性和重复加载。类加载的时候把会把类的class文件的类信息,常量,静态变量等载入方法区,并且在堆中生成Class对象

然后链接过程->验证则是检查字节码是否符合JVM的规范,准备则是为静态变量分配空间并赋0值,但是final修饰的就会赋值,解析就是将符号引用替换为直接引用

最后初始化就是调用<clinit>对成员变量和静态变量的赋值。对于类的初始化的时机:

④讲讲对象的创建过程?

答:①首先要去检查类是否被加载,如果没有的话就要先去加载这个类,通过加载,链接(验证,准备,解析),初始化去加载到内存中。

②然后就是为对象在堆中分配一块空间像分配空间的方式也有两种指针碰撞(内存规整--serial,parall)和空闲列表(不规整,cms),通过根据堆中的内存是否规整来进行选择。

③将对象属性进行初始化为零。

④进行必要的对象头设置,像类元信息,GC分代年龄,hashcode等。

⑤最后再执行init进行初始化,初始化成员变量的值,执行构造块,调用构造方法完成对象的创建。

⑤讲一讲JVM中的垃圾回收算法?

答:主要有三种垃圾回收算法,

①首先是复制算法,将内存分成两个相同大小的区,分别为from和to。使用时只使用一个,当进行垃圾回收时,首先将from区的垃圾标记,然后把存活的对象全部放去to区,再清空from区,执行完之后把二者身份互换。复制算法优点就是没有内存碎片,但是会造成一部分的内存浪费而且存活数量很大时性能会很差。

②然后就是标记-清除算法,分为两个阶段,一个是标记阶段,为每个对象进行标记看是不是被GC ROOT引用;第二个阶段是清除阶段,该阶段对死亡的对象进行清除,执行 GC 操作。虽然效率高,但是会产生内存碎片。

③标记-整理算法,在标记-清除算法的基础之上,在垃圾回收之前把存活的对象整理在一端,解决了内存碎片的问题但是移动了对象需要去更新引用。

⑥讲一讲JVM的分代回收模型?

答:因为JVM的三种垃圾回收算法各有所长各有所短,所以JVM不会只是用其中的一种所以就有分代回收算法。①首先模型被分为了新生代和老年代,一般是1:2,新生代又被分为了伊甸园,from区和to区。②新生代一般根据大部分对象朝生夕死的特点使用复制算法,当新生代空间不足时,触发minor gc,将伊甸园和from区中存活的对象复制到to中并且对象年年龄+1,到对象年龄到达一定数值(15)后会被放到老年代中,然后再将死亡的对象回收掉,最后交换from和to区。③当老年代空间不足时,先会尝试minor gc,如果还不够就会触发full gc。④当对象的大小超过新生代的空间,并且minor gc之后也没用,会直接晋升到老年代。

⑦讲一讲垃圾回收器?

答:首先垃圾回收器大致可以分为三类,串行,吞吐量优先和响应时间优先。

①串行则是SerialGC。算法使用的是复制算法和标记-清除算法,简单高效但只适用于单cpu和小内存环境。

②吞吐量优先ParallelGC。算法使用的是复制算法和标记-清除算法,多线程并发处理,适用于多核CPU和大内存环境,但是响应时间长。

③响应时间优先则是CMS垃圾回收器。使用的是标记清除算法。CMS工作过程:初始标记阶段,会暂停所有的线程即STW标记所有的根对象。并发标记阶段,与应用线程并发进行标记所有的可达对象。重新标记阶段,在这个阶段,CMS垃圾回收器会暂停应用程序的线程,重新标记所有的根对象和可达对象。并发清除阶段,在这个阶段,CMS垃圾回收器会和应用程序并发回收掉所有的垃圾。其优点是响应时间快,并发标记和清除可配置性强,但是会产生内存碎片。

④G1垃圾回收器。G1会把堆内存划分为多个大小相同的Region并且逻辑上还有分代的思想,然后整体上是标记-整理算法,两个区域直接则是复制算法。其工作过程其实跟CMS差不多,都是先初始标记,并发标记,最终标记和并发清除,但G1最大的一个特点,就是可以设置一个垃圾回收的预期停顿时间。而且在并发清除的时候会进行一个筛选回收就是如果设置了预期的停顿时间,那么他就会优先选择垃圾多的Region先回收以达到低停顿高性能,刚好也符合HotSpot的热点地区的特征。

⑧讲一讲堆和栈?

答:首先堆和栈都是java中用来存储程序运行时的数据的内存区域。区别的话有:

①分配方式:堆是动态分配,有java虚拟机自动管理,而栈的话是静态分配的,是由编译器管理的。

②存储内容:堆一般是存储对象的实例或者一些引用类型数据的,而栈的话一般是存储方法的调用,局部变量,返回地址,参数等数据类型。

③内存管理:堆的内存分配和回收都是jvm的垃圾回收机制负责,而栈的话就是你调用一个方法然后方法返回或者退出之后,占内存会自动释放掉。

④空间大小:堆(且动态扩展)>栈(大小固定)。

⑤存储速度:堆<栈。

⑨TomCat为什么要打破双亲委派机制?以及如何打破双亲委派模型?

答:因为双亲委派机制为了确保唯一性,安全性和类的重复加载,对同一个类只会被加载一次。但是TomCat作为一个Web服务器应用,其内部可以有多个独立的Web应用,多个应用之间可能会有相同的类出现,这就会导致应用用不了自己的类。所以TomCat为每一个应用都生成一个WebappClassLoader去加载各自的应用去达到应用之间的隔离。其实Tomcat也不是说完全打破了双亲委派机制。更多的是续写了双亲委派机制,加入了以下几个类加载器,然后在WebAPPClassLoader中绕过父级的类加载器,直接自己去加载的。

Common ClassLoader:Tomcat和Web应用共享的jar包

Catalina ClassLoader:Tomcat私有的jar包

Shared ClassLoader:Web应用之间可以共享的jar包

WebApp Classloader:加载Web应用私有的jar包

打破双亲委派机制的方法:①继承ClassLoader类,重写loadclass方法,在方法中可以自定义类加载使用的类加载器。②使用线程上下文加载器,可以通过java.lang.Thread类setContextClassLoader()这个方法去设置当前类的类加载器

⑩JVM调优

答:JVM的参数有很多:

相关推荐
程序员志哥6 小时前
JVM系列(十三) -常用调优工具介绍
jvm
后台技术汇6 小时前
JavaAgent技术应用和原理:JVM持久化监控
jvm
程序员志哥6 小时前
JVM系列(十二) -常用调优命令汇总
jvm
黄油饼卷咖喱鸡就味增汤拌孜然羊肉炒饭6 小时前
聊聊volatile的实现原理?
java·jvm·redis
_LiuYan_9 小时前
JVM执行引擎JIT深度剖析
java·jvm
王佑辉10 小时前
【jvm】内存泄漏的8种情况
jvm
工业甲酰苯胺10 小时前
JVM简介—1.Java内存区域
java·jvm·python
yuanbenshidiaos1 天前
c++---------数据类型
java·jvm·c++
java1234_小锋1 天前
JVM对象分配内存如何保证线程安全?
jvm
40岁的系统架构师1 天前
1 JVM JDK JRE之间的区别以及使用字节码的好处
java·jvm·python