Java内存回收机制

首先什么是内存回收,内存回收就是释放掉那些在内存中已经没有用的对象。
java的内存回收是自动进行的。
java的内存回收主要在java的堆上进行,java的堆中存储了大量的对象实例,所以java堆也叫GC堆。

如何判断哪些对象是没有用的。
1、引用计数
比较古老的回收算法。原理是此对象有一个引用,即增加一个计数,删除一个引用则减少一个计数。垃圾回收时,只用收集计数为0的对象。此算法最致命的是无法处理循环引用的问题。
2、根搜索
这个算法的基本思路就是通过一系列的名为”GC Roots“的对象作为起始点,从这些节点开始向下搜索,搜索搜走过的路径为引用链,当一个对象到GC Roots没有任何引用链相连接时,则证明此对象是不可用的,不可达的,应该被回收。

那么java的内存回收有哪些算法呢?
1.标记-清除
这种算法主要是标记出所有需要回收的对象(从引用根节点开始标记所有被引用的对象,第二阶段遍历整个堆,把未标记的对象清除。此算法需要暂停整个应用,同时,会产生内存碎片),然后回收所有的需要回收的对象。 但是有一个明显的缺点,采用这种算法之后会发现内存块回收之后就不连续了,这就导致了在下一次想分配一个大内存块的时候无法分配。


2.标记-清除-压缩
这种垃圾收集算法主要是对上面的算法进行了优化,内存回收了对内存进行了一次优化压缩。这样回收后内存块的连续性又比较强了,但是这种算法会涉及到不停的内存间的拷贝和复制,性能会非常差。


3.标记-清除-复制
这种算法会将内存空间分配成两块相同的区域A和B。当内存回收的时候,将A中的内存块拷贝到B中,然后一次性清空A。
但是这种算法会对内存要求比较大一些,并且长期复制拷贝性能上也会受影响。



结合以上方法
java产生一种分代收集的算法。
基于对对象生命周期分析后得出的垃圾回收算法。把对象分为年新生代、老年代、永久代,对不同生命周期的对象使用不同的算法(上述方式中的一个)进行回收。现在的垃圾回收器(从J2SE1.2开始)都是使用此算法的。

- Young(新生代)
年轻代分三个区。一个Eden区,两个Survivor区(Survivor0和Survivor1)。大部分对象在Eden区中生成。当Eden区满时,还存活的对象将被复制到Survivor0区,当这个Survivor0区满时,此区的存活对象将被复制到Survivor1区,当这个Survivor区也满了的时候,从第一个Survivor区复制过来的并且此时还存活的对象,将被复制“老年代(Old)。需要注意,Survivor的两个区是对称的,没先后关系,所以同一个区中可能同时存在从Eden复制过来 对象,和从前一个Survivor复制过来的对象,而复制到年老区的只有从第一个Survivor去过来的对象。而且,Survivor区总有一个是空的。
- Old(老年代)
年老代存放从新生代存活的对象。一般来说老年代存放的都是生命期较长的对象。
- Permanent(永久代)
用于存放静态文件,如今Java类、方法等。持久代对垃圾回收没有显著影响,但是有些应用可能动态生成或者调用一些class,例如Hibernate等,在这种时候需要设置一个比较大的持久代空间来存放这些运行过程中新增的类。持久代大小通过-XX:MaxPermSize=<N>进行设置。


补充:
GC有两种类型:Scavenge GC和Full GC。
- Scavenge GC
一般情况下,当新对象生成,并且在Eden申请空间失败时,就好触发Scavenge GC,堆Eden区域进行GC,清除非存活对象,并且把尚且存活的对象移动到Survivor区。然后整理Survivor的两个区。
- Full GC
对整个堆进行整理,包括Young、Old和Permanent。Full GC比Scavenge GC要慢,因此应该尽可能减少Full GC。有如下原因可能导致Full GC:
  - Old被写满
  - Permanent被写满
  - System.gc()被显示调用

  - 上一次GC之后Heap的各域分配策略动态变化

引用的新概念:引用分为强引用、软引用、弱引用、虚引用,这四种引用强度依次逐渐减弱

1、强引用:强引用就是指程序代码中普遍存在的,类似 Object a = new Object() 这类的引用,只要引用还存在,垃圾收集器永远不会回收掉该引用对象所占内存
2、软引用:软引用用来描述一些还有用,但并非必需的对象。对于软引用关联着的对象,在内存不足,将要发生内存溢出异常之前,将会把这些对象列入回收范围之中并进行第二次回收。
3、弱引用:用来描述非必需对象,强度比软引用更弱一些,被弱引用关联的对象只能生存到下一次垃圾收集发生之前,当垃圾收集器工作时,无论当前内存时候足够,都将其回收。
4、虚引用:它是最弱的一种引用关系。一个对象是否有虚引用存在,完全不会对其生存时间构成影响,也无法通过虚引用来取得对象实例。它的唯一目的就是希望能在这个对象被收集器回收时收到一个系统通知。
·
      垃圾回收他是在虚拟机空闲的时候或者内存紧张的时候执行的,什么时候回收不是由程序员来控制的,这也就是java比较耗内存的原因之一。
      还有在垃圾回收的时候当检测到对象没有用了,需要被回收的时候并不会马上被回收,而是将其放入到一个准备回收的队列,去执行finalize方法。等到下次内存回收的时候要是他还是没有被任何人引用的话,就将其给回收了。(如果在finalize方法中重新给对象加个引用,这样对象是有可能不会被回收的)不过finalize方法不推荐使用,他跟C++中的析构函数不同,我们既不能确定什么时候他回被回收,也不能保证这个方法一定会被执行。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值