JVM三问

个人学习经验

Posted by lujunzizi on July 13, 2018

“Yeah It’s on. ”

前言

最近看《windows核心编程》看到了线程安全的部分,想到以前看《深入理解jvm》的时候也看过并发的篇章于是又重新看了一遍《JVM》,写一些个人心得笔记吧。
之所以取名为“JVM三问”,是因为主要是从GC、Java类加载机制、Java内存模型三个方面来做的一些总结,写的有些仓促,因为周末有事情,下周开始准备跟比赛相关的事情,以后自己翻翻再做修缮。 —

正文

1.什么时候一个对象会被GC?

JVM采用根搜索算法来标记需要回收的对象,通过一系列名为GCRoots的对象作为起始点,当一个对象到gcroots没有任何引用链相连,则说明这个对象是不可用的,它们会被判定为可回收的对象,
它将会被第一次标记且进行一次筛选,筛选的条件为此对象是否需要执行finalize()方法,当对象没有覆盖finalize方法或者finalize()方法已经被虚拟机调用过,虚拟机将这俩种情况都视为“没有必要执行”。
对象判定为有必要执行finalize()方法后,这个对象会被放到一个F-queue的队列中,并在稍后有一条由虚拟机自动建立的、低优先级的finalizer线程去执行。
稍后GC会对F-queue中的对象进行第二次标记,如果对象“拯救”了自己,将他移出即将回收的集合。

2.GC策略的分类

标记-清除算法:标记出所有回收的对象,标记完成后统一回收所有被标记的对象。 优点:简单。 缺点:效率问题,标记和清除的效率都不高;空间问题,标记清除后会产生大量不连续的内存碎片,如果在以后的运行过程中需要分配较大的对象而无法找到足够的连续空间时不得不提前触发另一次垃圾回收操作;
标记-复制算法:将可用内存按照容量划分为大小相等的两块,每次只使用其中的一块,当一块内存使用完了,将存活着的对象复制到另一块上面,然后再把已使用过的内存空间一次清理掉。 优点:实现简单、运行高效,不需要考虑内存碎片的问题,内存分配时只要移动堆顶指针,按顺序分配内存即可 缺点:两个复制区 导致可用内存降低,在对象存活率较高的时候就要执行较多的复制操作导致效率降低。 标记-整理算法:标记过程与标记-清除算法一致,后续步骤不是直接对可回收对象进行清理,而是让所有存活的对象朝一端移动,然后直接清除掉端边界以外的内存。 优点:不会产生碎片,

3.类加载器分为哪几类

启动类加载器
扩展类加载器
应用程序类加载器 因为这个类加载器是ClassLoader中的getSystemClassLoader()方法的返回值,所以一般也称为系统类加载器。

4.每个类加载器各加载哪些类

启动类加载器:加载\lib中的类,或者被-Xbootclasspath参数所指定的路径中被虚拟机识别的类,启动类加载器无法被java程序直接引用。 扩展类加载器 加载\lib\ext中的类,或者被java。Ext.dirs系统变量所指定的路径中的所有类库,开发者可以直接使用扩展类加载器。 应用程序类加载器 加载用户类路径(ClassPath)所指定的类库。

5.什么是双亲委派模型

类加载器之间的层次关系称之为双亲委派模型(此处应当有图),双亲委派模型要求除了顶层的启动类加载器以外,其余的类加载器都应当有自己的父类加载器。

6.双亲委派模型的意义

Jvm在加载一个类的时候,首先不会自己去尝试加载这个类,把这个请求委派给这个类加载器的父类加载器去完成,每个层次的类加载器都是如此,
因此所有的加载请求最终都会传给顶层的启动类加载,只有当父类加载器反馈自己无法完成这个加载请求(在它的搜索范围内没有找到所需的类)时,子类加载器才会尝试自己去加载。
java类随着它的类加载器一起具备了一种带有优先级的层级关系,比如java.lang.object类,无论哪一个类加载器要加载这个类,最终都是委派给启动类加载器进行加载,因此object类在程序的各种类加载器环境中都是一个类,保证了java程序的稳定运作。

7.如何自定义自己的类加载器,自己的类加载器与java类加载器的关系如何处理

继承自java 的应用程序类加载器,实现loadclass和findclass的方法,当加载一个类的时候会按照双亲委派模型的工作流程工作。

8.jvm内存分为几个部分

jvm内存分为程序计数器、对象堆、方法区、java虚拟机栈、本地方法栈、运行时常量池、直接内存。

9.对象从创建到销毁是怎样在这些部分里面存活和转移的

对象在对象堆中创建(句柄池,常量池),第一个minor GC后如果存活,由eden区进入s区,在minor GC一定次数后,如果依然存活(动态对象年龄判定)进入老年代(或者存活由于对象太大直接进入老年区)

10.内存的哪些部分参与GC的回收

主要是对象堆,方法区也参与但是一个方法的卸载判断条件过于复杂。

11.java的内存模型是如何设计的?

Java内存模型的主要目标是定义程序中各个变量的访问规则。规定所有的变量存储在主内存,每条线程都有自己的工作内存。

12.volatile关键字

数据可视性,如果一个对象被声明为volatile,那么所有涉及该对象的修改,jvm总线会给所有的内存寄存器发出通知,将这个对象的寄存器高速缓存清除,这样他要再次使用这个对象必须重新从内存处取出。(这段话不记得从哪儿看来的了。)
volatile的第二个语义是禁止指令重排序优化。