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.随着程序的访问量增长,程序的底层是肯定要优化的,内存空间也是很重要的一个地方~

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

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

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Python数据科学

使用Pandas&NumPy进行数据清洗的6大常用方法

数据科学家花了大量的时间清洗数据集,并将这些数据转换为他们可以处理的格式。事实上,很多数据科学家声称开始获取和清洗数据的工作量要占整个工作的80%。

2462
来自专栏专注 Java 基础分享

垃圾收集机制与内存分配策略

Java 语言与其他编程语言有一个非常突出的特点,自动化内存管理机制。而这种机制离不开高效率的垃圾收集器(Garbage Collection)与合理的内存分配...

4249
来自专栏小樱的经验随笔

51Nod 1016 水仙花数 V2(组合数学,枚举打表法)

1016 水仙花数 V2 基准时间限制:1 秒 空间限制:131072 KB 分值: 160         难度:6级算法题 水仙花数是指一个 n 位数 ...

2887
来自专栏张善友的专栏

Immutable(不可变)集合

不可变集合,顾名思义就是说集合是不可被修改的。集合的数据项是在创建的时候提供,并且在整个生命周期中都不可改变。 为什么要用immutable对象?immutab...

2106
来自专栏Spark学习技巧

JVM的垃圾回收算法

JVM的垃圾回收算法 一,如何判断对象已经消亡 1,引用计数算法 一个对象如果没有任何引用指向它,就可认为该对象已经”消亡“,这种方法有个缺点就是无法检测到引用...

21610
来自专栏陈树义

JVM系列第8讲:JVM 垃圾回收机制

在第 6 讲中我们说到 Java 虚拟机的内存结构,提到了这部分的规范其实是由《Java 虚拟机规范》指定的,每个 Java 虚拟机可能都有不同的实现。其实涉及...

974
来自专栏一个番茄说

让你的编译器更懂你,写出更棒的Swift

自从Swift诞生以后,苹果就一直在努力让它变得更好,更快。相比更加灵活的Objective-C,Swift显得更加老实本分。但是,如果你真的对它了解之后,你会...

803
来自专栏鸿的学习笔记

python源码阅读笔记之GC(一)

python源码阅读: 参考书籍:《python源码剖析》 摘要:写这个系列的目的呢,是想为python的学习画上一个暂时的句号,接下来的重点应该是scala这...

1222
来自专栏HansBug's Lab

3038: 上帝造题的七分钟2

3038: 上帝造题的七分钟2 Time Limit: 3 Sec  Memory Limit: 128 MB Submit: 662  Solved: 302...

2854
来自专栏web前端教室

javascript 红皮高程(11)

为革命,重学JS高程,预备...齐! 3.4.7 object哈,对象。找不着对象的同学们,建议看看JS高程,就能找着对象了。 ECMAScript中的对象,是...

2045

扫码关注云+社区

领取腾讯云代金券