您的位置:首页 > 编程语言 > Java开发

初识java这个小姑娘(二)

2017-12-20 22:46 363 查看


妙解垃圾回收机制

周一,早高峰!!!

 

五个字,说尽心中的绝望!!!

 

一段考验一个人耐力、智力、开车技术以及脾气的路。 我把车开进了一个没有红绿灯的丁字路口,然后就没有然后了。

来自三个方向的大车小车开始在不大的一块空间里开始互相斗智斗勇,但是最终的结果永远是伤敌一千,自损八百。

这种崩溃的心情应该很多人都体会过,特别是本来不用迟到,但是堵车却能让你迟到上好几个小时。

在所有人都陷入绝望的时候,交警同志终于到达现场,开始疏散车辆。

那些给我贴罚单的“讨厌”的人,一下子变成了无比高大的存在。

此时已经是快要九点半了,快要两个小时的时间,我竟然只挪动了两米不到。

 

一刹那间,我终于体会到什么是垃圾回收机制,你能体会吗?

使用java进行编程,但是从来没有去思考过这个问题的小伙伴们?

这个巨大的丁字路口,可以理解为内存,可以允许有限的车辆在里面通行。

当车辆不停地始驶入,就像是无数的线程都要放到内存中,需要被处理。

终于,内存爆了。接下来的一幕就是内存溢出,停止工作。

那些已经被不会被使用的垃圾线程依然停留在内存当中,就好像横在我眼前的这个大卡车。(当然对我来说,除了我之外的所有的车辆都是垃圾,应该被回收掉)

这个时候,内心里有一个声音:如果有人能把它们带走就好了。

于是,交警来了,他就是java中的垃圾回收机制。

他以极快的速度把所有停滞在内存当中的废弃线程快速的清除出去。

于是,终于,一切又开始高速的运转开来。

 
在java之前众多的编程语言,都是通过编程人员自己来清除内存中已经被废弃掉的无用线程或者对象。

使得程序员的精力过多的消耗在了系统上。

如果系统自身可以完成这部分工作,程序员就能够更多的去关注业务本身而不是系统效率。

这样做的好处是解放程序的大脑,但是坏处也是显而易见的。

那就是系统提供的垃圾回收机制无法做到像人工操作一样,在第一时间就知道代码中的对象已经使用完毕,而立即清除。

系统需要固定的时间和固定的方式来做这件事情。

好在通过jdk不断升级,java语言的维护团队对效率做了很大的优化。

在开始详细介绍垃圾回收机制的工作原理之前,有一个小小的思维拓展。

 

我记得刚开始接触到java的时候,老师讲对象在内存中的存储时,总是告诉我,引用存储在栈中,而对象是存储在堆中。

老实说,即使是几年之后,如此抽象的讲解依然让我无法理解java的底层工作到底是怎样的?

而所谓的栈,堆又到底是什么,根本没有一个解释能让人直观的理解程序在内存中到底是怎样进行工作的。

 

那么说一些我自己的理解。

 

众所周知,计算机所有的工作原理是建立在二进制上。

所谓二进制,课本告诉我们是由1,0组成的一种进制,而原因是机器只能识别二进制。

好吧,关于二进制其实也是云雾缭绕的存在,我现在特别不理解在课堂上老师怎么能如此官面的解释二进制。

我们输入指令,计算机要做的事情有两个,第一是识别这道指令,第二是执行这道指令。

那么是否可想想象二进制的存储方式就是一种信息的表达,就是把1,0按照机器能够识别的记录顺序进行排序,而计算机通过阅读这一串1,0组成的机器码,了解了指令的内容。

然后它处理完这道指令之后,又以1,0的方式反馈给我们,这种二进制的信息存储最终被翻译成了我们能够识别的文字,音乐,图像等等。
说到底,二级制就是一种信息的存储方式罢了。

那么所谓的栈,是否可以理解为java虚拟机将内存中的某一块区域指定为栈,这块区域是通过1,0 的方式存储指令。
内存就像二元矩阵,而虚拟机划分了一块作为栈或者堆。
这种指定本身也不是固定,也许下一次虚拟机指定了另外的地方。

如此是否可以更好地理解所谓的栈和堆呢。

不过是强行划分的内存区域,并且在这个区域中是按照java虚拟机指定的规则进行数据的存储和阅读的。
不知这样的理解是否正确,还请指正。

 

下面说说java的回收机制到底是怎么工作的。

1.stop-the-world这几个字一度让我觉得这不是代码,而是诗。

是怎样的一个诗人,才能给这段程序如此诗意的一个名字。

Stop-the-world意味着 JVM 因为要执行GC而停止了应用程序的执行。

当Stop-the-world发生时,除了GC所需的线程以外,所有线程都处于等待状态,直到GC任务完成。

GC优化很多时候就是指减少Stop-the-world发生的时间。

 

2.垃圾回收机制是怎样辨别哪些对象是需要进行回收的?
在此时我们大体梳理一下整个过程。

在Java中,开发人员无法直接在程序代码中清理内存,而是由垃圾回收器自动寻找不必要的垃圾对象,并且清理掉他们。

垃圾回收器会在下面两种假设(hypotheses)成立的情况下被创建(称之为假设不如改为推测(suppositions)或者前提(preconditions))。    

 

大多数对象会很快变得不可达    

只有很少的老年对象(创建时间较长的对象)指向新生对象的引用

 

这些假设我们称之为弱年代假设(weak generational hypothesis)。

 

为了强化这一假设,虚拟机将其物理上划分为两个–新生代(young generation)和老年代(old generation)。

 

新生代(Young generation):绝大多数最新被创建的对象会被分配到这里,由于大部分对象在创建后会很快变得不可到达,所以很多对象被创建在新生代,然后消失。对象从这个区域消失的过程我们称之为”minor GC“。

老年代(Old generation):对象没有变得不可达,并且从新生代中存活下来,会被拷贝到这里。其所占用的空间要比新生代多。也正由于其相对较大的空间,发生在老年代上的GC要比新生代少得多。对象从老年代中消失的过程,我们称之为”major GC“(或者”full GC“)

 

新生代的构成
为了更好地理解GC,我们现在来学习新生代,新生代是用来保存那些第一次被创建的对象,他可以被分为三个空间
一个伊甸园空间(Eden)

两个幸存者空间(Survivor)
一共有三个空间,其中包含两个幸存者空间。每个空间的执行顺序如下:
绝大多数刚刚被创建的对象会存放在伊甸园空间。

在伊甸园空间执行了第一次GC之后,存活的对象被移动到其中一个幸存者空间。

此后,在伊甸园空间执行GC之后,存活的对象会被堆积在同一个幸存者空间。

当一个幸存者空间饱和,还在存活的对象会被移动到另一个幸存者空间。

之后会清空已经饱和的那个幸存者空间。

在以上的步骤中重复几次依然存活的对象,就会被移动到老年代。
如果你仔细观察这些步骤就会发现,其中一个幸存者空间必须保持是空的。

如果两个幸存者空间都有数据,或者两个空间都是空的,那一定标志着你的系统出现了某种错误。

老年代GC处理机制
老年代空间的GC事件基本上是在空间已满时发生,执行的过程根据GC类型不同而不同。

 

到此为止,是否可以更加直观的理解所谓垃圾回收机制. 这是我对java语言的一些简单理解,原创作品,欢迎关注同名微信订阅号:程序员与工匠。

欢迎各位大大扫描下方二维进 行关注。

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息