JVM

jvm是啥?

jvm是java的虚拟机,他将程序变为字节码class文件,然后通过jvm处理到操作系统平台。

class文件的加载过程:加载:查找和导入class文件

            验证:验证里面的字节码文件是否符合要求

            准备:给字节码文件里面的对象变量分配空间

            解析:将符号引用变为直接引用

            初始化操作

类加载器:启动类加载器-拓展类加载器-应用程序类加载器

双亲委派:当一个类收到类加载器加载请求时,它会将这个类加载请求给他的父类加载器,只有当父类加载器不能完成时,子类加载器才会进行类加载。

双亲委派的作用时保证不同类加载器加载的都是同一个对象。

 

1.内存模型以及分区。

内存模型主要由方法区、堆、栈、本地方法栈、程序计数器。

方法区:供各线程共享的运行时的内存区域。存储了类信息,运行时常量池等,还存放static变量。

堆:通过new关键字,创建对象都会使用到堆内存。存放所有new出来的对象,只保存对象本身,不保存对象的引用。

栈:程序运行时的内存空间。主要由栈帧结构组成,调用一个方法即压入一个栈帧。是线程私有的,因此不存在垃圾回收机制。8种基本数据类型、对象的引用与实例方法都保存在栈内存中。

本地方法栈:主要是native方法。

程序计数器:记录当前线程jvm指令的执行地址。线程私有,不存在垃圾回收机制。

 

2.一个java程序的执行流程。

java文件,编译器生成字节码class文件,然后经过类加载器、字节码校验器与解释器到操作系统平台。

 

3.JVM如何判断一个对象能否被GC,可以被视为root的都有哪几种类型?

  1. 引用计数法。即当对象被引用一次就+1,如果失效了就-1,变成了0之后就可以判断可以被垃圾回收。但JVM并没有采用这种方式,因为不能很好的解决循环利用。比如A与B互相引用,但程序已经没有再引用A和B了。
  2. 引用链法。通过一种GC ROOT对象来进行判断,GC ROOT代表那种不能够删除的对象。如果对象有一条链能够到达该GC ROOT则判断该对象不能进行回收,反之则可以回收。

可以作为GC ROOT的对象:

  • System Class:由系统类加载器(System Class Loader)加载的类。自定义类加载器加载的类不一定是 GC ROOT对象。
  • Thread:激活状态的线程
  • Stack Local: Java方法的local变量或参数(存在于所有Java线程当前活跃的栈帧里,它们会指向堆里的对象)
  • JNI Local:JNI方法的local变量或参数。JNI是Java Native Interface的缩写,中文为JAVA本地调用。
  • JNI Global - 全局JNI引用
  • 正在被用于同步的各种锁对象
  • JVM自身存有的对象,比如类加载器等。

4.强软弱虚引用的区别以及GC对他们执行怎样的操作?

强引用:在程序中普遍存在,一般为直接引用。永远都不会对其进行垃圾回收。

Object object = new Object();
String str = "hello";

 

软引用:用来描述一些还有用但非必须的对象。内存不足时会对其进行回收。

弱引用:用来描述非必须对象。会被垃圾回收。

虚引用:虚引用的存在不会对对象的生存时间构成任何影响,为一个对象设置虚引用的唯一目的就是能在这个对象被收集器回收时收到一个系统通知。

 

垃圾回收算法?

1.标记清除算法。从GC ROOT 开始采用引用链法标记引用链上对象,然后清除未标记的对象。

优点:没有产生额外的内存消耗,内存利用率高。

缺点:回收的垃圾对象并不一定是连续的,因此导致存在不连续的空间,产生内存碎片。

2.标记整理算法。开始同样从GC ROOT开始采用引用链法标记引用链上的对象,然后将标记的对象移动到内存一侧。将剩下的空间回收。

优点:解决了标记清除算法产生的内存碎片问题。

缺点:效率较低。

3.复制算法。把内存空间一分为二,每次只使用其中的一块。当进行GC时,将存活着的对象复制到另一块上。然后把已使用过的这一块内存清理。

优点:解决内存碎片问题,效率较高。

缺点:将内存的可用大小压缩了一半。

 4.分代回收。详情见下。

 

堆内存为什么要分为新生代与老年代?

堆内存被分为新生代与老年代。新生代又被细分为Eden和Survivor区,最后Survivor由FromSpace和ToSpace组成。发生在新生代的GC为Minor GC 。在老年代中的GC则为Major GC。

新生代一般存放很快就要被GC(垃圾回收)的对象,新生代采用的复制算法。在Minor GC时会将还存活的对象放到一个Survivor区中,然后对Eden与另外一个Survivor进行清理。

老年代一般存放经历了多次GC依然存活的对象。老年代一般采用标记清除或者标记整理算法。

 

新生代各区的比例?

Eden-Survivor    8 :1 :1。 对象先放在Eden区中,当快满了触发Minor GC时。采用复制算法将Eden区与Survivor中from区的内存复制到to区。按照这个比例和复制算法可以比较高效的利用内存与解决内存碎片的问题。

 

新生代怎么进入老年代?

1.分配担保机制。当Minor GC时,一个Survivor区存放不了那么多时就会进入老年代。

2.超过所设置的内存大小的对象会进入老年代。

3.当进行一次Minor GC后,还存在的元素就会+1,一般当到所设置的临界点时会进入老年代。

 

垃圾收集器?

https://www.cnblogs.com/chenpt/p/9803298.html

单线程垃圾收集器:采用单线程进行垃圾回收,当在垃圾回收过程中,会暂停所有工作线程,也是就说是一直STW的。

多线程垃圾收集器:采用多个线程进行垃圾回收,提高效率,但是同样在垃圾回收过程中,其他线程一直是STW。

多线程并发垃圾收集器:比如CMS垃圾收集器。在进行垃圾回收过程中,其他线程一样的进行工作,降低了STW时间。

到现在是G1垃圾收集器。

 

CMS垃圾收集器:老年代收集器,采用标记-清除算法与多线程并发的垃圾回收方式降低了STW时间。

垃圾回收过程:

初步标记:标记GC ROOT直接可达对象,这是STW的。耗时较短

并发标记:垃圾回收线程与其他工作线程一起工作。进行可达性分析,耗时较长

重新标记:标记并发过程中的可达对象,这也是STW的

并发清除:与其他线程一起工作清除垃圾。

缺点:

使用标记-清除算法,可能会产生碎片。

不能处理浮动垃圾。因为采用并发清除 在标记后 清除前 产生的垃圾在这一次垃圾回收过程中不能被回收。

 

G1收集器:

克服了CMS收集器产生垃圾碎片的缺点,其次他可以精确的控制停顿时间,也就是STW时间。

G1垃圾收集器引入了分区的思想,弱化了分代的概念。它将内存空间分成很多区,将这些区域分成新生代Eden区与survivor区,老年代,还有一个区单独存放那些内存很大的对象,一般是大于二分之一个region区。G1收集器将对象从一个区复制到另外的区,避免了内存碎片这个问题。然后引入了一个remember set 记录引用信息,这样就不必进行整堆扫描了。最后G1垃圾收集器会判断哪一个区最具有回收价值,对其进行回收。

初始标记

并发标记

重新标记

筛选清除:选择最具有垃圾回收价值的分区进行回收。

 

G1垃圾回收器为什么可以控制停顿时间。

因为垃圾回收器在最后进行回收时会对每个分区进行排序,选择最具有回收价值的分区回收。因为其他垃圾收集器都是回收整个垃圾因此时间是不可控的,而G1垃圾收集器进行筛选回收的话,可以设定一定的垃圾回收时间。

 

Minor GC 与Full GC

当eden区内存不足的时会Minor GC   Minor GC一直是STW的。

 

当老年代内存不足时会Full GC

当新生代中进入老年代的内存很大时可能会Full GC

调用System.gc Full GC

 

posted @ 2020-03-12 17:44  xxcnotes  阅读(117)  评论(0编辑  收藏  举报