目录
JVM主要组成部分及其作用?
JAVA程序运行机制详情
JVM运行时的数据区
堆和栈的区别?
Java垃圾回收机制
Java中有哪些引用类型?
如何判断对象是否可以被回收?
JVM中的永久代会发生垃圾回收吗?
JVM有哪些垃圾回收算法?
JVM有哪些垃圾回收器?
简述分代垃圾回收器是怎么工作的?
CMS垃圾回收器介绍
1. 收集过程
2、CMS三色标记
说一下类装载的执行过程?
什么是双亲委派模型?
JVM主要组成部分及其作用?
JVM包含两个子系统和两个组件:
两个子系统:Class Loader(类加载器)、Execution engine(执行引擎);
类装载:根据给定的全限定名类名(如:java.lang.Object)来加载Class文件到运行时数据区(Runtime data area)中的方法区(method area)。
执行引擎:执行classes中的命令。
两个组件:Runtime data area(运行时数据区)、Native Interface(本地接口)。
运行时数据区:我们常说的JVM内存。
本地接口:与native libraries交互,是其他编程语言交互的接口。
作用:首先通过编译器把java代码转换成字节码,类加载器(Class Loader)再把字节码加载到内存中,将其放在运行时数据区(Runtime data area)的方法区,而字节码文件只是JVM的一套指令集规范,并不能直接交给底层操作系统去执行,因此特定的命令解析器执行引擎(Execution engine),将字节码翻译成底层的系统指令,再交给CPU去执行,而这个过程需要调用其他语言的本地库接口(Native Interface)来实现整个程序的功能。
JAVA程序运行机制详情
java程序运行机制步骤:
1、首先利用IDE集成开发工具编写Java源代码,源文件的后缀为.java;
2、再利用编译器(javac命令)将源代码编译成字节码文件,将字节码文件的后缀名为.class
3、运行字节码的工具由解释器(java命令)来完成。
JVM运行时的数据区
1、java堆:线程共享,存储对象实例和数组;
2、方法区(元空间):线程共享,存储虚拟机加载的类信息、常量、静态变量;
3、java虚拟机栈:存储局部变量表、操作数栈、动态链表、方法出口;
4、本地方法栈:为虚拟机调用Native方法服务的;
5、程序计数器:当前线程所执行的字节码行号指示器;
堆和栈的区别?
1、物理地址:
堆:物理地址分配对象是不连续的,性能慢些。
栈:物理地址分配是连续的,遵循先进后出原则,性能快。
2、内存分别:
一般堆的大小远远大于栈。
3、存放内容:
堆:线程共享,存储对象实例和数组。
栈:线程私有,局部变量、操作数栈、返回结果。
Java垃圾回收机制
在java中,程序员是不需要主动的去释放一个对象的内存的,而是由虚拟机自行执行。在JVM中,有一个垃圾回收线程,它是低优先级的,在正常情况下是不会执行的,只有在堆内存不足或者虚拟机空闲时,才会触发执行,扫描那些没有被任何引用的对象,将它们添加到回收的集合中,进行回收。
Java中有哪些引用类型?
1、强引用:发生GC的时候不会被回收;
2、软引用:有用但不是必须的对象,在发生内存溢出之前会被回收;
3、弱引用:有用但不是必须的对象,在下一次GC时会被回收;
4、虚引用:作用就是在GC时返回一个通知。
如何判断对象是否可以被回收?
一般有两种方法来判断:
1、引用计数器法:为每个对象创建一个引用计数,有对象引用是计数器+1,引用被释放是计数器-1,当计数器为0时就可以被回收了。缺点:不能解决循环引用问题。
2、可达性分析算法:从GC Roots开始向下搜索,搜索所走过得路径称为引用链。
当一个对象到GC Roots没有任何引用链相连时,则证明此对象可以被回收。
JVM中的永久代会发生垃圾回收吗?
垃圾回收不会发生在永久代,如果永久代满了或者超过了临界值,会触发Full GC。
JVM有哪些垃圾回收算法?
1、标记-清除算法:标记无用对象,然后清除回收。缺点:效率不高,无法清除垃圾碎片。
2、复制算法:按照容量划分二个大小相等的区域,当一块用完的时候将活着的对象复制到另一块上,然后把已使用的内存空间一次清理掉。缺点:内存使用率不高,只有原来的一半。
3、标记-整理算法:标记无用对象,将所有存活对象向一端移动,然后清除掉端边界以外的内存。
4、分代算法:根据对象存活周期不同将内存划分为几块;一般是新生代、老年代和永久代,新生代基本采用复制算法,老年代采用标记-整理算法。
JVM有哪些垃圾回收器?
回收新生代的收集器:Serial、PraNew、Parallel Scavenge
回收老年代的收集器:Serial Old、Parallel Old、CMS
回收整个java堆的G1收集器
简述分代垃圾回收器是怎么工作的?
新生代默认的空间占比总空间的1/3,老生代的默认占比是2/3。
新生代使用的是复制算法,新生代里有3个分区:Eden、To Survivor、From Survivor,它们的默认占比是8:1:1,它们的执行流程如下:
1、把Eden 和 From Survivor存活的对象放入To Survivor区;
2、清除Eden 和 From Survivor分区;
3、From Survivor 和 To Survivor分区交换,From Survivor 变 To Survivor, To Survivor变From Survivor。
每次在From Survivor到To Survivor移动时,存活的对象年龄+1,当年龄到达15(默认配置是15)时,升级为老年代。(对象也会直接进入老年代)。
老年代空间不足就会触发Full GC,一般使用标记-整理算法。
CMS垃圾回收器介绍
CMS是老年代回收器,只能回收老年代的对象,在收集过程中可以与用户线程并发操作。CMS牺牲了系统的吞吐量来追求收集速度,适合追求垃圾收集速度的服务器上。CMS收集器可以通过参数:-XX:+UseConcMarkSweepGC启用。
1. 收集过程
CMS收集器是基于算法标记-清除来实现的:
1、初始标记:记录能被GC Root直接引用的对象,触发一次STW,但是这次STW很快,因为在标记的过程中不会标记一整条引用链的对象。
2、并发标记:从GC Roots的直接引用对象开始依次扫描,这个过程需要比较多的时间,用户线程和GC线程同时执行,不会产生STW,因为在扫描的过程中用户线程还在不断的执行所以可能会出现标记过的对象又变成了垃圾。
3、重新标记:重新标记需要Stop The World,这个阶段是为了修正在并发标记阶段产生的浮动垃圾,对标记过的对象进行。
4、并发清除:GC线程和用户线程同时进行,开始正式清除未被标记的垃圾,在此阶段也会产生垃圾(浮动垃圾),产生垃圾后无法清除,只能留待下一次GC。
CMS收集过程如下图所示:
收集过程总结:
1、在初始标记和重新标记有两次stop the world的标记操作
2、初始标记只标记GC Root关联的对象,速度很快
3、在初始标记触发STW的时候,它的标记方式还是原始的更改对象头MarkWord的GC标记字段,但是在并发标记阶段,因为是用户线程和GC线程同时在跑,所以采用的是三色标记的方式进行垃圾标记。
2、CMS三色标记
1、白色:对象的默认颜色,从GC Root开始扫描,如果对象是不可达对象的话就是白色,也就是垃圾对象,在并发清理的时候会清理掉。
2、灰色:当前对象已经被扫描过,但是当前对象所依赖的其他对象还没有被扫描。
3、黑色:当前对象和它所依赖的对象都已经被扫描过,不会对黑色对象和引用的对象再次进行扫描。
三色标记使用在并发标记阶段,使用三色标记会导致两个问题,一个是漏标,一个是多标。
漏标的解决方案
CMS使用增量更新的方式解决三色标记漏标问题。
增量更新:将新增的引用维护到一个集合里面,将引用的源头变成灰色,等待重新标记阶段再重新进行一次扫描。比如:当A的引用指向了B,则会将B变成灰色,并将B放在一个新增引用的集合里面;在重新标记阶段会将B作为根节点继续向下扫描。
说一下类装载的执行过程?
类装载分为以下5个步骤:
1、加载:根据查找路径找到相应的class文件然后导入;
2、验证:检查加载的class文件的正确性;
3、准备:给类中的静态变量分配内存空间;
4、解析:虚拟机将常量池中的符号引用替换成直接引用的过程。符号引用就理解为一个标示,而直接引用直接指向内存中的地址;
5、初始化:对静态变量和静态代码块执行初始化工作。
什么是双亲委派模型?
如果一个类加载器收到类加载的请求,首先它不会自己加载这个类,而是把这个请求委派给父类加载器去完成,每一层的类加载器都是如此,这样所有的加载请求都会被传送到顶层的启动类加载器中,只有当父类加载器无法加载请求时,子类加载器才会尝试去加载类。
(当一个类收到加载请求时,不会自己去加载这个类,而是将其委派给父类,有父类去加载,如果此时父类不能加载,反馈给子类,由子类去完成加载。)