JVM基础
一.什么是JVM
定义:即Java虚拟机,Java程序的运行环境(Java二进制码的运行环境)
二.jvm,jre,jdk的比较
jre:即Java运行环境
jdk:即Java 语言的软件开发工具包,包含了JAVA的运行环境(JVM+Java系统类库)和JAVA工具。
三.JVM组成部分
(1)ClassLoader:类加载器,Java代码编译成二进制字节码后通过类加载器进去JVM内存结构
(2)JVM内存结构
方法区:存储类的区域
堆:存放类的实例化对象
虚拟机栈,程序计算器,本地方法栈:实例化对象调用方法时用到。
(3)执行引擎
解释器:方法执行时每行代码有解释器逐行进行执行。
即时编译器:对被频繁调用的代码进行优化后执行。
垃圾回收:对堆里面中不再被引用的对象进行回收。
(4)本地方法接口:Java代码不方便实现的功能,通过本地方法接口来调用底层操作系统提供的功能和方法
垃圾回收机制(该机制存在于堆中)
如何判断对象可以被回收
1.引用计数法:一个对象被其他变量所引用,让这个对象的计数加一,如果被引用了两次,就加二,如果某一个变量不再引用它了,计数就减一。当它的引用计数变为0的时候就判断是垃圾可以回收了。但这个算法存在一个弊端:循环引用的问题。
如图,对象A和B引用对象都为1,虽然没有谁在引用它们两,但是也不能通过引用计数法判断可以被回收。造成内存上的泄露。
2.可达性分析算法(JVM使用的算法)
2.1.根对象(GC Roots):通俗来说,就是肯定不能被当成垃圾来回收的对象被称为根对象。
2.2.具体实现:扫描堆中的对象。看看是否能够沿着GC Roots对象为起点的引用链找到该对象,找不到,表示可被以回收;
2.3.那些对象可以作为GC Roots?
a:java虚拟机栈中的引用的对象。
b:方法区中的类静态属性引用的对象.(一般指被static修饰的对象,加载类的时候就加载到内存中。)
c:方法区中的常量引用的对象。
d:本地方法栈中的native引用的对象。
2.4.注意:即使可达性算法中的不可达对象,也不是一定要马上被回收,还有可能被抢救下。要真正宣告对象死亡需要经过两个过程。
(1).可达性算法分析后没有发现引用链。
(2).查看对象是否有finalize方法,如果有重写且在方法内完成自救(比如再建立引用),还是可以抢救一下
3.Java中的引用类型
强引用:无论内存是否足够,不会回收。所以强引用是造成内存泄露的主要原因。但是如果中断了强引用和某个对象的关联,赋值为null,就有可能被回收。
软引用:垃圾回收时,内存不足时,回收该引用关联的对象。
弱引用:垃圾回收时,无论内存是否足够,都会回收。
虚引用:任何时候都可能被垃圾回收器回收。
垃圾回收算法
1.标记清除法
1.1步骤
第一步:标记,沿着GC Root对象的引用链去找,扫描整个堆对象的过程中查找是否被根对象所引用,如果一个根对象都没有被引用,那么就可以被当成垃圾进行回收。
第二步:清除,把垃圾对象占用的内存空间进行释放;(注意误区:释放不是把垃圾对象每个字节进行清零的操作,而是把对象所占用内存的起始结束的地址记录下来,放在一个叫空闲的地址列表里,下次分配新的对象的时候,就去空闲地址列表去找是否有足够的空间容纳新对象,如果有,就进行分配。并不会进行清零的操作。)
1.2优缺点:速度快,效率高;因为只需要记录垃圾对象的起始结束地址就可以完成垃圾回收了。不需要进行其他额外的操作。但是容易产生内存碎片,如图。新的对象如果需要连续的空间,而垃圾对象不一定是连续的,导致于不能给分配足够大的内存空间。就会造成内存碎片这种概念。
2.标记整理法
2.1步骤
第一步也是标记,与上述的标记清除法中的标记一样。
第二步整理
将堆中的垃圾对象清理,将可用的对象向前移动,连续空间更加多了。避免了内存碎片的产生。
3.复制算法
3.1步骤
第一步:将内存区域划分成内存相等的两块区域。开始的区域为from区域,复制后的为to区域。
第二步:标记
第三步:复制
将from区域中的不是垃圾对象复制到to区域中,复制过程中也会完成碎片的整理,不会产生内存碎片,然后清除from区域的垃圾对象。
第四步:交换区域。
将TO区域和FROM区域交换位置,TO区域变为FROM区域,
3.2优缺点:不会产生内存碎片,但是内存使用率不高,只使用了原来的一半。
分代回收(一种垃圾回收机制)
定义和成员:实际的JVM机制,不会单独采用一种垃圾回收算法,一般都是结合前面三种算法协同工作,具体的实现就是JVM中的分代回收机制。
将堆内存划分成两块区域。一块为新生代(默认占1/3),一块为老年代(默认占2/3)
新生代:用完了随时可以丢弃的对象存储在新生代中。新生代又分为三个区域,伊甸园,幸存区From和TO
老年代:存储长时间使用的对象,垃圾回收的频率较低。
具体实现
1.创建一个新的对象时,新的对象默认占用伊甸园区域。
2.当创建对象增多至伊甸园内存不够时,就会触发Minor GC,采用可达性分析算法,标记出可以回收的垃圾,使用复制算法,把存活的对象复制到幸存区To中。接着将幸存下来的对象生命加一。然后清除伊甸园中的垃圾对象,最后将幸存区TO和From交换位置。
===>>>
===>>>
3.第二次垃圾回收的时候,将伊甸园中的存活的对象放入幸存区TO中,计数为1,之前幸存区中存活且本次也存活的对象也放入幸存区From中,计数为2,接着清除伊甸园中和幸存区From中的垃圾对象,然后幸存区to和from交换位置。
4.当幸存区对象的计数达到某个默认值(默认计数是15),说明这个对象价经常使用,价值比较高,就把他放入老年代。
5.当老年代内存不够用的情况下,先会触发Minor GC,如果空间仍不足,就会触发Full GC。一般使用标记整理的执行算法。