Jvm垃圾回收算法

一,JVM概念

JVM是Java Virtual Machine(Java虚拟机)的缩写,JVM是一种用于计算设备的规范,它是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来实现的。

二,堆与栈

栈是运行时的单位,堆是存储的单位。
栈解决的是一个程序的运行,就是如何进行数据处理等问题,堆解决的是存储数据的问题,就是在哪里存储数据并且存储到哪里,怎样存储。这样说的话可以理解成堆就是为栈服务的,一个程序中可以没有堆,但是不可没有栈,没有栈是不可以运行的。
堆是一种动态分配内存机制,它的内存容量比栈大,一般在堆中存储的都是一些较大的数据,就是对象,数组,接口类型等。然而栈相当于一个线程,栈是一个运行单位,因此里面存储的信息是跟线程(就是一个程序)相关的,包括引用类型,基本数据类型等。堆只负责存储数据,所以堆是线程共享的。
把堆和栈分开实现了分而治之的思想,就相当于动态分离,使逻辑更清晰,隔离化效果更好。堆和栈的分离,并且堆中的数据是共享的,所以达到了内存共享的目的,并且节省了空间。就是因为这种堆和栈的分离,才使Java垃圾回收机制成为了一种可能。

三,引用类型

对象引用类型分为强引用,软引用,弱引用和虚引用。
强引用(StrongReference):就是我们一般生命对象时虚拟机产生的引用,强引用环境下,虚拟机严格判断当前是否被强引用,如果被强引用,则不会被垃圾回收。
软引用(SoftReference):一般作为缓存来引用,与强引用的区别是,软引用在垃圾回收时会根据剩余的内存来决定会不会对软引用的垃圾进行回收。如果空间不足,就会进行回收。
弱引用(WeakReference):弱引用也是被作为缓存使用,但是弱引用一旦检查出来立马被回收掉,因此其生命周期在一个垃圾回收周期内。
虚引用(PhantomReference):这个引用存在的唯一目的就是在这个对象被收集器回收时收到一个系统通知,被虚引用关联的对象,和其生存时间完全没关系。

四,垃圾回收机制

1,哪些内存需要回收?
我们都知道JVM的内存结构包括五大区域:程序计数器,虚拟机栈,本地方法栈,堆区,方法区,但是其中程序计数器,虚拟机栈,本地方法栈都是随着线程的生而生,灭而灭,所以这几个区域的内存分配和回收都具备确定性,所以不必要考虑。而Java堆区和方法区都是不一样的,它们的内存分配是动态的。
垃圾收集器在对堆区和方法区进行回收前,首先要确定这些区域的对象哪些可以被回收,哪些暂时还不能回收,这就要用到判断对象是否存活的算法!
2,判断对象是否存活
①引用计数算法
引用计数算法是垃圾收集器中很老的一种策略,在这种方法中,堆中每个对象实例都有一个引用计数,当这个对象被创建时,就将该对象实例分配给一个变量,变量计数设置为1,当任何变量被赋值为这个对象的引用时,计数器就加1,当这个引用过了生命周期或者设置为一个新值时,计数器减1,当计数器为0时,就被当作垃圾回收。
优点:引用计数器可以很快地执行,对程序不被打乱的情况下比较有利。
缺点:无法检测出循环引用。
②可达性分析算法
从一个根节点GC ROOT开始,寻找对应的引用节点,找到这个节点后,继续寻找这个节点的引用节点,这样就形成一个引用链,当一个对象到GC ROOT没有任何引用链时,则证明对象是不可用的。其实未达到的对象也并非是非“死”不可的,还需要进行两次标记,具体两次标记我还不理解,所以暂时不写,有明白的希望大家可以提出来。
3,回收触发机制
①,当申请内存,内存不够用的时候
②,对堆进行整理的时候。
4,方法区的垃圾回收
①废弃的常量
咱们就以字面量为例,如果一个字符串已经进入常量池,但是常量池中没有进行引用,那么这个字符串就会被当作废弃的常量回收
②无用的类
该类的所有实例被回收,即Java堆中不存在该类的实例。
加载该类的ClassLoader被回收。
无法通过反射访问该类的方法。
5,垃圾回收算法
①标记-清除算法
分为两个阶段,一是标记需要回收的对象,二是回收所有被标记的对象。
这种算法两种效率都不高,并且标记清楚后会残留大量的内存碎片,当一个大的对象需要申请大块内存的时候内存会出现不够用的情况。所以不得不出发再次的内存清理。
②复制算法。
复制算法是为了解决效率问题而出现的,它分为两块内存,每次只用一块,当这一块用完了,就把还活着的对象全部都复制都另一块内存,然后把这一块内存全部清理掉。这样也解决了内存残留碎片的问题。
缺点:在存活率高的情况下,复制效率会变低,并且内存占用量大。
3标记-整理算法
标记整理算法分为两步,让所有的存活对象向一端移动,然后把另一端的垃圾全部回收清理,这样的话即提高了效率并且减少了内存占用量。
④分代收集算法。
分代收集算法就是把内存分为几块,然后根据各块的特点选择适合的收集算法。大批对象死去、少量对象存活的(新生代),使用复制算法,复制成本低;对象存活率高、没有额外空间进行分配担保的(老年代),采用标记-清理算法或者标记-整理算法。
分代的垃圾回收策略,是基于这样一个事实:不同的对象的生命周期是不一样的。因此,不同生命周期的对象可以采取不同的回收算法,以便提高回收效率。

年轻代(Young Generation)
  所有新生成的对象都被放到年轻代中,年轻代的目标就是尽可能快速的收集掉那些生命周期短的对象,年轻代分为三个区,一个Eden区和两个Survivor区,一般Eden区占用80%,每个Survivor区各占10%,当Eden区满的时候,就会把活着的对象复制到第一个Survivor区,当这个Survivor区满时,此区的存活对象将被复制到另外一个Survivor区,当这个Survivor区也满了的话,就会把第一个Survivor区存活的对象复制给年老代,需要注意,Survivor的两个区是对称的,没先后关系,所以同一个区中可能同时存在从Eden复制过来 对象,和从前一个Survivor复制过来的对象,而复制到年老区的只有从第一个Survivor去过来的对象。而且,Survivor区总有一个是空的。同时,根据程序需要,Survivor区是可以配置为多个的(多于两个),这样可以增加对象在年轻代中的存在时间,减少被放到年老代的可能。
年老代(Old Generation)
存放的是生命周期比较长的对象。  
持久代(Permanent Generation)
 用于存放静态文件,如Java类、方法等。持久代对垃圾回收没有显著影响,但是有些应用可能动态生成或者调用一些class,例如Hibernate 等,在这种时候需要设置一个比较大的持久代空间来存放这些运行过程中新增的类。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值