个人理解,所学有限,若有不当,还请指出
1.JVM是由哪些部分组成,运行流程是什么?
JVM为java虚拟机,是java程序的运行环境(其实是java字节码文件的运行环境),能够实现一次编写,到处运行,并且拥有垃圾回收机制
JVM是由1.类装载子系统2.运行时数据区3.字节码执行引擎4.本地方法调用四个大部分组成。
运行流程是: java文件在经过javac的命令之后变成了字节码文件,此时jvm启动,类装载子系统将字节码文件加载到了jvm中,然后经过运行时数据区,把字节码加载到内存中,而字节码文 件只是JVM的一套指令集规范,并不能直接交给底层系统去执行,而是通过执行引擎运行,而后执行引擎将字节码翻译为底层系统指令,再交由CPU 执行去执行,以此来实现整个程序的功能。
2.什么是程序计数器?
程序计数器是用来记录下一条代码(字节码)的地址的。(个人理解)因为多线程机制,一个程序在运行时,可能半路上就去执行另一个线程了,若是另一个线程执行完之后呢,就可以通过程序计数器记录的地址,继续执行上一个线程的代码,而不用重新开始,这样能大大提高执行效率。
(资料理解)java虚拟机对于多线程是通过线程轮流切换并且分配线程执行时间。在任何的 一个时间点上,一个处理器只会处理执行一个线程,如果当前被执行的这个线程 它所分配的执行时间用完了【挂起】。处理器会切换到另外的一个线程上来进行 执行。并且这个线程的执行时间用完了,接着处理器就会又来执行被挂起的这个 线程。 那么现在有一个问题就是,当前处理器如何能够知道,对于这个被挂起的线 程,它上一次执行到了哪里?那么这时就需要从程序计数器中来回去到当前的这 个线程他上一次执行的行号,然后接着继续向下执行。 程序计数器是JVM规范中唯一一个没有规定出现OOM的区域,所以这个空间也 不会进行GC。
3.你能给我详细的介绍Java堆吗?
这里先说明一下jvm中的堆在哪里。。。运行时数据区分为多个部分组成:堆,栈,本地方法栈,方法区/元空间,程序计数器五个内存区域组成。 而java堆就是用来存储数组和对象实例的地方,那些new出来的对象都是放到这里的。java堆的内部呢根据分代模型分为年轻代和老年代(比例为1:2)两个部分,其中年轻代又分为三个部分(eden,s0,s1(这里的s0和s1统称为survivor)(此处占比为8:1:1))
4.能不能解释一下方法区?
(个人总结:其中放置的是常量,静态变量,类信息这些)包含class{类信息}(,classloader{加载类},)运行时常量池
- 常量池可以看作是一张表,虚拟机指令根据这张常量表找到要执行的类名,方法名,参数类型,字面量等信息
5.什么是虚拟机栈?
栈又叫线程栈,每一个线程运行时所需要的内存空间即为栈,(因为其先进后出的特定而得),
每个栈由多个栈帧(frame)组成,对应着每次方法调用时所占用的内存,从mian方法进入之后,开辟了一块mian方法的栈帧区域,而后运行到其他方法的时候就会开辟出另一块栈帧区域用于运行该方法,因此mian方法最先开始,最后结束。每个线程只能有一个活动栈帧,对应着当前正在执行的那个方法。
6.垃圾回收是否涉及栈内存?
JVM中的垃圾回收主要是指在堆中发生的gc操作,垃圾回收涉及堆内存,不涉及栈内存,运行时,当栈帧弹栈之后,内存就会被释放。
7.栈内存分配越大越好吗?
一般栈内存分配1024k,并不是越多越好,栈帧内存越大,可活动的线程就会越少。
8.方法内的局部变量是否线程安全?
如果局部变量没有离开方法的作用区域就是线程安全的,如果是局部变量引用了对象,并逃离方法的作用范围,需要考虑线程安全
9.你听过直接内存吗?
直接内存并不属于内存结构,并不由jvm进行管理,是虚拟机的系统内存,常见于NIO操作时,用于数据缓冲区,它分配回收成本较高,但是读写性能高
10.堆栈的区别是什么?
1.存储对象不同:堆存储数组和对象实例,栈存储方法调用和局部变量。
2.堆拥有垃圾回收机制,而栈没有
3.堆是线程公有的,栈是线程私有的
11.什么是类加载器,类加载器有哪些?
类加载器,(类装载子系统)将字节码 文件加载到JVM中,从而让Java程序能够启动起来。除此之外,类加载器还会负责加载程序所需要的资源。
类加载器的种类:启动类加载器(用于加载 JAVA_HOME/jre/lib目录下的类库),扩展类加载器(要加载JAVA_HOME/jre/lib/ext目录中的类 库),应用类加载器(用于加载开发者自己的类),自定义类加载器(实现自定义类加载规则(摆脱双亲委派的方法))。
12.什么是双亲委派模型?
(个人理解)双亲委派模型是发生在类加载子系统中的,在加载类的时候,经过应用类加载器,扩展类加载器,启动类加载器,在加载一个类的时候会先将类委托给目前类加载器的上级,如果上级加载器有这个类,就由上级加载器进行加载,如果上级的上级有就让其加载,如果都没有再由目前类加载器加载
(资料回答)如果一个类加载器在接到加载类的请求时,它首先不会自己尝试去加载这个类, 而是把这个请求任务委托给父类加载器去完成,依次递归,如果父类加载器可以 完成类加载任务,就返回成功;只有父类加载器无法完成此加载任务时,才由下 一级去加载。
13.JVM为什么采用双亲委派机制?
避免类的重复加载,当父类已经加载后则无 需重复加载,保证唯一性,避免API被恶意修改
14.说一下类装载的执行过程?
类从加载到虚拟机中开始,直到卸载为止,它的整个生命周期包括了:加载、验 证、准备、解析、初始化、使用和卸载这7个阶段。其中,验证、准备和解析这 三个部分统称为连接(linking)
加载:查找和导入class文件。验证:保证加载类的准确性。准备:为类变量分配内存并且设置类变量初始值。解析:把类中的符号引用转换为直接引用。初始化:对类的静态变量,静态代码块进行初始化操作。使用:JVM开始从入口方法开始执行用户的程序代码。卸载:当用户程序执行完毕之后,HVM便开始销毁创建的Class对象。
15.简述Java垃圾回收机制?(GC是什么?为什么要GC)
为了让程序员更专注于代码的实现,而不用过多的考虑内存释放的问题,所以, 在Java语言中,有了自动的垃圾回收机制,也就是我们熟悉的GC
(除了Java语言之外,C#、Python等语言也都有自动的垃圾回收机制)
16.对象什么时候可以被垃圾器回收?
如果要确定一个对象是否是垃圾对象一般有两种方式:
1.引用计数法:一个对象被引用了一次,在当前的对象头上递增一次引用次数,如果这个对象的 引用次数为0,代表这个对象可回收,但是当对象间出现了循环引用的话,则引用计数法就会失效(所以这个方法其实也不太行)
优点: 1.实时性较高,无需等到内存不够的时候,才开始回收,运行时根据对象的计 数器是否为0,就可以直接回收。2. 在垃圾回收过程中,应用无需挂起。如果申请内存时,内存不足,则立刻报 OOM错误。3. 区域性,更新对象的计数器时,只是影响到该对象,不会扫描全部对象。
缺点:1. 每次对象被引用时,都需要去更新计数器,有一点时间开销。 2.浪费CPU资源,即使内存够用,仍然在运行时进行计数器的统计。3. 无法解决循环引用问题,会引发内存泄露。(最大的缺点
2.可达性分析算法:现在的虚拟机采用的都是通过可达性分析算法来确定哪些内容是垃圾对象。 会存在一个根节点【GC Roots】,引出它下面指向的下一个节点,再以下一个 节点节点开始找出它下面的节点,依次往下类推。直到所有的节点全部遍历完 毕。
17.JVM 垃圾回收算法有哪些?
1.标记清除算法:
标记清除算法,是将垃圾回收分为2个阶段,分别是标记和清除。 1.根据可达性分析算法得出的垃圾进行标记 2.对这些标记为可回收的内容进行垃圾回收
缺点:1.效率较低,标记和清除两个动作都需要遍历所有的对象,并且在GC时,需要 停止应用程序,对于交互性要求比较高的应用而言这个体验是非常差的。 2.(重要)通过标记清除算法清理出来的内存,碎片化较为严重,因为被回收 的对象可能存在于内存的各个角落,所以清理出来的内存是不连贯的。
2.复制算法:
复制算法的核心就是,将原有的内存空间一分为二,每次只用其中的一块, 在垃圾回收时,将正在使用的对象复制到另一个内存空间中,然后将该内存空间 清空,交换两个内存的角色,完成垃圾的回收。 如果内存中的垃圾对象较多,需要复制的对象就较少,这种情况下适合使用该 方式并且效率比较高,反之,则不适合。
优点: 在垃圾对象多的情况下,效率较高 清理后,内存无碎片 缺点: 分配的2块内存空间,在同一个时刻,只能使用一半,内存使用率较低
3.标记整理算法:
标记压缩算法是在标记清除算法的基础之上,做了优化改进的算法。和标记清 除算法一样,也是从根节点开始,对对象的引用进行标记,在清理阶段,并不是 简单的直接清理可回收对象,而是将存活对象都向内存另一端移动,然后清理边 界以外的垃圾,从而解决了碎片化的问题
优缺点同标记清除算法,解决了标记清除算法的碎片化的问题,同时,标记压缩 算法多了一步,对象移动内存位置的步骤,其效率也有有一定的影响。 与复制算法对比:复制算法标记完就复制,但标记整理算法得等把所有存活对象 都标记完毕,再进行整理
4.分代收集算法:
在java8时,堆被分为了两份:新生代和老年代,它们默认空间占用比例是 1:2 对于新生代,内部又被分为了三个区域。Eden区,S0区,S1区默认空间占用 比例是8:1:1 具体的工作机制是有些情况: 1)当创建一个对象的时候,那么这个对象会被分配在新生代的Eden区。当 Eden区要满了时候,触发YoungGC。 2)当进行YoungGC后,此时在Eden区存活的对象被移动到S0区,并且当前 对象的年龄会加1,清空Eden区。 3)当再一次触发YoungGC的时候,会把Eden区中存活下来的对象和S0中的 对象,移动到S1区中,这些对象的年龄会加1,清空Eden区和S0区。 4)当再一次触发YoungGC的时候,会把Eden区中存活下来的对象和S1中的 对象,移动到S0区中,这些对象的年龄会加1,清空Eden区和S1区。 5)对象的年龄达到了某一个限定的值(默认15岁 ),那么这个对象就会进 入到老年代中。 当然也有特殊情况,如果进入Eden区的是一个大对象,在触发YoungGC的时 候,会直接存放到老年代。当老年代满了之后,触发FullGC。FullGC同时回收新生代和老年代,当前只 会存在一个FullGC的线程进行执行,其他的线程全部会被挂起。 我们在程序 中要尽量避免FullGC的出现
18.简述分代收集算法。
在java8时,堆被分为了两份:新生代和老年代【1:2】,在java7时,还存在一 个永久代
对于新生代,内部又被分为了三个区域。Eden区,S0区,S1区【8:1:1】 当对新生代产生GC:MinorGC【young GC】 当对老年代代产生GC:Major GC 当对新生代和老年代产生FullGC: 新生代 + 老年代完整垃圾回收,暂停时间长, 应尽力避免
1.新创建的对象,都会先分配到eden区,2.如果eden区没有空间了就会发生minor gc操作,幸存的对象就会进入幸存区
3.当幸存区对象熬过几次回收(最多15次),晋升到老年代(幸存区内存不足 或大对象会导致提前晋升)
19.MinorGC、 Mixed GC 、 FullGC的区别是什么?
MinorGC【young GC】发生在新生代的垃圾回收,暂停时间短(STW)
Mixed GC 新生代 + 老年代部分区域的垃圾回收,G1 收集器特有
FullGC: 新生代 + 老年代完整垃圾回收,暂停时间长(STW),应尽力避免
(STW:暂停所有应用程序线程,等待垃圾回收的完成,进行JVM目的就是要减少STW的发生)
20.说一下 JVM 有哪些垃圾回收器?
串行垃圾收集器
并行垃圾收集器
CMS(并发)垃圾收集器
G1垃圾收集器
串行垃圾收集器:Serial和Serial Old串行垃圾收集器,是指使用单线程进行垃圾回收,堆内存较 小,适合个人电脑 Serial 作用于新生代,采用复制算法 Serial Old 作用于老年代,采用标记-整理算法 垃圾回收时,只有一个线程在工作,并且java应用中的所有线程都要暂停 (STW),等待垃圾回收的完成。
并行垃圾收集器:Parallel New和Parallel Old是一个并行垃圾回收器,JDK8默认使用此垃圾回收器 Parallel New作用于新生代,采用复制算法 Parallel Old作用于老年代,采用标记-整理算法 垃圾回收时,多个线程在工作,并且java应用中的所有线程都要暂停(STW), 等待垃圾回收的完成。
CMS(并发)垃圾收集器:CMS全称 Concurrent Mark Sweep,是一款并发的、使用标记-清除算法的垃圾回 收器,该回收器是针对老年代垃圾回收的,是一款以获取最短回收停顿时间为目 标的收集器,停顿时间短,用户体验就好。其最大特点是在进行垃圾回收时,应 用仍然能正常运行
G1垃圾回收器(重要):应用于新生代和老年代,在**JDK9之后默认使用G1** 划分成多个区域,每个区域都可以充当 eden,survivor,old, humongous, 其中 humongous 专为大对象准备 采用复制算法 响应时间与吞吐量兼顾 分成三个阶段:新生代回收、并发标记、混合收集 如果并发失败(即回收速度赶不上创建新对象速度),会触发 Full GC。
21.强引用、软引用、弱引用、虚引用的区别?
强引用最为普通的引用方式,表示一个对象处于有用且必须的状态,如果一 个对象具有强引用,则GC并不会回收它。即便堆中内存不足了,宁可出现 OOM,也不会对其进行回收 软引用表示一个对象处于有用且非必须状态,如果一个对象处于软引用,在 内存空间足够的情况下,GC机制并不会回收它,而在内存空间不足时,则会 在OOM异常出现之间对其进行回收。但值得注意的是,因为GC线程优先级较 低,软引用并不会立即被回收。 弱引用表示一个对象处于可能有用且非必须的状态。在GC线程扫描内存区域 时,一旦发现弱引用,就会回收到弱引用相关联的对象。对于弱引用的回 收,无关内存区域是否足够,一旦发现则会被回收。同样的,因为GC线程优 先级较低,所以弱引用也并不是会被立刻回收。 虚引用表示一个对象处于无用的状态。在任何时候都有可能被垃圾回收。虚 引用的使用必须和引用队列Reference Queue联合使用