前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java垃圾回收的细节

Java垃圾回收的细节

作者头像
用户2141593
发布2019-02-20 10:52:31
4610
发布2019-02-20 10:52:31
举报
文章被收录于专栏:Java进阶Java进阶

大家都知道 java 的垃圾回收机制,java有自己的垃圾回收器来自动回收垃圾。本人对于垃圾回收机制以前也就知道java的垃圾回收器是自动回收垃圾的,有这么回事,知道有finalize和system这两个方法而已,别人都跟我说,你知道java虚拟机有垃圾回收这回事就可以了,你不用操心这个的,我也一直深信不疑,并感叹java 虚拟机真神奇!直到我对 java 的理解逐渐加深后,才发现并不是那么回事!

下面说个小故事:有一个小土豪家里请了一个保姆每天打扫卫生,但不知道这个保姆会什么时候来; java的垃圾回收器就相当于我们请的这个保姆,它会清理垃圾但你无法控制他什么时候来清理。

我们要弄清垃圾回收机制要弄清楚以下三个问题:

1.什么样的垃圾需要被回收?

2.什么时候进行垃圾回收?

3.怎样回收这些垃圾?

1如何判断对象变成了垃圾?

java 中有一个算法叫做可达性算法,这个算法的思路是把一个 “GC Roots” 的对象作为起始点,从这些节点往下搜索,搜索的路径称为引用链,当一个对象到 GC Roots 之间没有任何引用链相连,(也就是从 GC Roots 到这个对象不可达)则可以证明该对象是不可用的,就会被当做垃圾回收的对象。

GC Roots 不指向了的对象就搜索要被回收的对象       任何对象被垃圾回收时都会至少经历两次标记的过程。

GC Roots不指向该对象时,标记一次,标记这次时该对象还没有真正被回收! 

2.什么时候进行垃圾回收?

在标记完第一次后,会判断该对象是否有必要执行finalize()方法,finalize方法会第二次标记该对象,一旦被第二次标记后,该对象就肯定会被垃圾回收器回收掉了!

如果有必要的话就会把这些对象放到一个叫做F-Queue的队列中,然后虚拟机会自动建立一个优先级比较低的线程去执行垃圾回收的方法,所以这里可以判断,在程序空闲时垃圾回收器会进行垃圾回收!

这里详细说一下finalize方法,该方法是属于object类的,它本身是一个空方法!特殊情况如果 finalize中该对象又指向了某个类变量,该对象就会逃过一劫不会被垃圾回收掉了。

不记得是在什么地方看到过说可以在finalize方法中释放程序资源!这种方法完全是不可取的,因为释放资源的代码放在 finally 代码块中去执行好得多,因为finally代码块收程序员控制,而finalize方法不被程序员所控!

3.怎样回收这些垃圾?

运行finalize方法,然后开始垃圾回收!

当前使用的虚拟机的垃圾收集都采用 分代收集 算法, 根据对象存货周期的不同将内存划分为几块。java堆分为:新生代和老年代,这样就可以根据各个年代的特点采用最适当的收集算法;

在新生代中每次垃圾收集时都有大批的对象死去,只有少量的存活,那就选用复制式算法来进行回收;

而老年代中因为对象存活率高,没有额外空间对它进行分配担保,就必须使用标记式算法来进行回收;

复制式:把内存分为大小相等的两块,每次只使用其中的一块,当这一块的内存用完了,就将还存活着的对象复制到另外一块储存空间去,然后把已使用过的内存空间一次全部清理掉。

(感觉这里也可以判断:当内存快满了的时候就会进行垃圾回收了)

标记式:分为    标记---清除算法 和 标记---整理算法  

标记清除:标记出所有要回收的对象,然后统一回收;这种方式效率低,还会产生大量的不连续内存碎片,很少使用了;

标记整理:标记出所有要回收的对象,然后让所有存活着的对象往一端移动,然后直接清理另外一端的垃圾;  

垃圾回收的过程中也进行了内存中的碎片 清理工作;                

要是有对内存方面还不是特别理解的小伙伴可以换一个方式来理解一下: 凡是主人不要了的东西统统都是垃圾!主人这里作为 GC Roots 对象 他不想跟某些东西产生关联,这些东西就自然的变成了垃圾!

保姆把家里所有的物品搜索一遍,看到新买的饮料还没有开盖,看到新鲜的橘子还散发着清新的香味,作为垃圾回收器的保姆很清楚这些东西都是新的不需要垃圾回收,但是保姆会把喝完了的饮料瓶、吃完了后剩下的橘子皮收集起来,(饮料瓶可以装水,橘子皮还可以泡茶,还有再利用功能就好比 GC Roots指向不到的对象只要重新指向了其他类对象的属性就会被再次激活)问主人是不是真的要把这些东西处理掉? 如果主人说是的话就执行finalize方法 ,进行二次标记,在某一个时间段进行垃圾清理工作。

垃圾多的时候把所有东西都放在一个袋子里,把几个不丢的东西拿出来,然后把整个袋子丢掉,这就叫复制式。

垃圾少的时候也把所有东西都放在一个袋子里,把几个要丢的垃圾拿出来丢掉,这就叫标记式。

总结:

1.GC Roots 指向不了的对象就搜索要被回收的对象  !

2.在程序空闲时垃圾回收器会进行垃圾回收!在内存快满的时候要进行垃圾回收!

3.执行finalize方法后会开始垃圾回收,新生代进行复制式回收,老年代进行标记式回收!

看到这里大家应该稍微明白为什么要注意垃圾回收了细节了吧?

1.因为执行垃圾回收方法的线程优先级很低,如果乱new对象,内存空间快满了的时候垃圾回收器会强行进行垃圾回收!

垃圾回收器工作时是要消耗系统资源的,这时势必会影响其他线程的运行,影响程序的效率!

2.让程序员有警惕的意识,能用StringBuffer 修改字符就不要 去用String 创造好几个对象再去拼接而占用内存!

能用Person p = new Person();  通过 引用变量 p  去调用方法 就不要用匿名的对象   new Person()去调用!

3.随着程序的访问量增长,程序的底层是肯定要优化的,内存空间也是很重要的一个地方~

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2016年08月01日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档