Jvm基础知识
Posted 猫吃于
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Jvm基础知识相关的知识,希望对你有一定的参考价值。
Java语言相对c的区别是动态分配内存和垃圾回收机制。
Jvm对对象进行回收不仅仅依靠一种方法来回收,而是根据对象生命周期不同来使用不同的算法回收对象
判断对象已死
Jvm要进行垃圾回收的前提是判断一个对象是否已死.jvm通过以下算法判断哪些对象存活.哪些对象死亡。
1 引用计数器算法
引用计数器算法是给对象添加一个引用计数器,有对象引用(a = new A())就+1,当引用失效(引用被替换,当前线程结束可视为引用失效)的时候计数器-1,任何时候引用计数器为0的时候就表明该对象已死不可引用,这种算法简单高效,在大部分情况下都没问题,但是不能处理两个对象循环引用的情况。所以引出第二种算法
2 可达性分析算法
可达性分析算法就是通过一系列的对象作为起点,这些起点叫做‘GC ROOTS’,从这些根节点向下搜索 ,搜索走过的路径叫做引用链,当一个对象没有在这条引用链上的时候那么GC判定该对象可被回收,可达性分析算法解决了对象相互引用的问题。
可以作为根节点的对象包括以下几种:
(1) 虚拟机栈中引用的对象,比如一些类加载器
(2) 方法区中的静态变量引用的对象,这也是为什么静态变量可以直 接类明调用的原因,因为该对象一直存活。
(3) 方法区中常量引用的对象。
(4) Native方法引用的对象,这些方法的底层引用的C语言的函数
垃圾回收算法
经过上述两种方法判断之后大部分的可回收对象都已经被标记,GC启动可以对这些对象进行回收。由于垃圾收集算法涉及大量细节,本次只介绍几种算法的思想。
标记-清楚算法
标记收集算法分为标记和清除两个阶段,标记阶段就是判定对象是否可回收阶段,就是上文提到的两个算法(引用计数器算法和可达性分析算法),标记完成之后开始对标记的对象进行清除释放内存,这种方法是最基础的算法,它所带来的问题是有两个1是效率问题,2是内存问题。效率问题是标记过程和清楚过程这两个过程的效率不算高,内存问题是清楚过程中虽然会释放大量的内存空间,但是这些内存空间都是碎片化的,此时如果新建一个大的对象,比如新建一个大小为1000的集合如果jvm中没有合适的内存大小那么不得不再次触发回收机制,造成性能耗费审值卡死,为了解决上述问题,出现了下面这种垃圾收集机制。
复制算法
复制算法是针对标记清楚算法的不足之处碎片化空间问题另一种回收算法。他将内存划分为大小相等的a,b两块,当使用a内存时,当这块内存用完之后就对这块内存中存活的对象复制到b内存上,同时彻底清楚a内存,反复循环。这种方法解决了碎片化空间的问题,但是代价是将内存缩小了一半。现代的商用虚拟机一般都采用这种方式,但是对内存初始分配不是粗暴的一本为二,而是经过专门研究将内存分为一块较大的Eden内存和两块较小的Servivor内存。每次使用Eden和Servivor中的一块,当回收的时候将两个已用内存中存活对象移动到另一个空置的Servivor内存上去。这三块内存的比例是8:1:1..。复制收集算法也存在一个问题,如果对象大量需要回收的情况下那么该方法没问题,如果对象存活率较高的时候那么复制算法的效率就会变低。
当代虚拟机一般使用复制算法来收集新生代。
标记-整理算法
标记整理算法针对复制算法出现对象大量存活的情况下出现的一种算法。顾名思义,标记过程仍然是同标记清楚算法一样,但是后续的‘清楚’并不是直接对对象进行回收,而是针对标记回收算法的碎片化空间问题进行的升级处理,将所有存活的对象‘整理移动’,然后直接清除掉死亡对象的那一片内存即可。
分代收集算法
当代虚拟机一般都采用这种方式来进行垃圾回收,主要是将对象根据存货对象的不用分为新生代和老年代,这样就可以根据不同年代对象的不同特点使用不用的算法来回收对象。
比如:新生代使用复制算法来回收,老年代使用标记整理算法或者标记清楚算法。
以上是关于Jvm基础知识的主要内容,如果未能解决你的问题,请参考以下文章