概述
在java中开发人员并不需要关心关心一个对象的消亡,内存的回收。因为java会自动回收垃圾对象。下面就来介绍下java中的垃圾回收。
垃圾对象:
表这个对象没有其他的变量引用了,这个对象就是垃圾对象。
当jvm启动后会开启一个守护线程,一直扫描jvm的内存区域,扫描垃圾对象。然后找一个合适的时间去回收这些对象占用的控件。
那如何扫描这些内存区域,如何回收呢?
以下就是一些常用的回收算法:
引用计数法:(count)
给每个对象添加一个计数器,当这个对象添加一个引用就加1。但是这个算法有一个致命的缺点,就是无法处理循环引用的情况,比如说:A引用B,B引用A,这时候我要销毁A,但是因为B引用了A所以我必须等B销毁后我才能销毁A;如果我这个时候要去销毁B,但是因为A又引用了B,所以我就要等A销毁后才能销毁B。所以就形成了这种死循环。
复制算法:(copying)
此算法将内存空间分为两块空间,每次只使用一个其中一个空间。执行垃圾回收是,遍历当前使用的空间,把正在使用的对象复制到另一块内存区域中,按顺序存储,然后将当前时候的内存区域全部清空。就不会出现碎片化的情况了。但是这个算法需要两倍的空间。
标记-清除算法(make–sweep)
分两个阶段,第一阶段从引用根节点开始标记所有被引用的对象,第二阶段遍历整个堆,把未标记的对象清除,此算法需要暂停整个应用,同时会产生内存碎片。
标记-整理算法
标记-整理算法就是标记-清除算法和复制算法的综合版本。
java中采用分代垃圾收集,分为:
Young(年轻代):分为三块:Eden,From,To,三块比例:8:1:1
Old(老年代)
Permanent(永久代)
jvm:一般采用分代垃圾回收,一般在新生代也就是年轻代和老年代为划分,划分成两部分进行分堆垃圾回收。
为什么分代?
为了提高对象内存分配和垃圾回收的效率。打个比方说如果不分代,所有的新创建的对象和以往的对象都在放在一起这样如果要回收某一个对象就要遍历所有对象。
什么是分代?
你可以理解成就是一个个过滤网,过滤掉的东西就是被jvm回收掉的对象。剩下的对象就放在老年代代中,然后在依次过滤。
新生代:
新生代的回收率特别高,分为三块空间,较大的一块为Eden,和两块较小的Survivor空间,比例为8:1:1。当Eden空间不足是jvm将发起一次Minor GC。每个对象都有一个阀值,每进行一次GC,对象的与之加1,当这个阀值达到15的时候就会从新生代中转移到老年代中。
是如何通过堆分代来进行垃圾回收呢?
新生代每进行一次GC,阀值加1。当新生代内存空间不足时会进行一次Minor GC。
首先绝大部分对象,在新生代中Eden块中创建,大对象直接在老年代中创建。假设新生代的Eden按数组的存放顺序存储,一共存放了5个数据。这时候进行了一次GC,下标为0,3的对象被回收了,这时候jvm通过复制算法将新生代的Eden中存活的对象,也就是下标为1,2,4的对象全部复制到新生代中Survivor那种的to块中按连续的内存存储,然后将新生代Eden中的所有对象全部回收。
如果不采用这种方式,当你0,3下标位置的对象,被回收了这两个位置就空了,就产生了碎片。浪费了存储空间。因此 采用这种分代垃圾回收机制。
当新生代中的Survivor中的to块中的对象的阀值达到15,就将这个对象转移到老年代中。
老年代中的GC就没有那么的频繁了。
绝大部分的对象都在 新生代(Young Generation) 中的Eden中诞生,然后程序使用完毕后将不在使用的对象回收,将剩余没有被回收的对象放入 Survivor Space(幸存空间) 中,如果Survivor Space(幸存空间),还没有被回收就会被放在Old generation(老年代中),最后在老年代中还没有被回收掉的对象就被放到 permanent永久代中。
最后
以上就是诚心短靴为你收集整理的java垃圾回收的全部内容,希望文章能够帮你解决java垃圾回收所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复