妙解垃圾回收机制

周一,早高峰。

一段考验一个人耐力、智力、开车技术以及脾气的路。

我把车开进了一个没有红绿灯的丁字路口,然后就没有然后了。

来自三个方向的大车小车开始在不大的一块空间里开始互相斗智斗勇,但是最终的结果永远是伤敌一千,自损八百。 这种崩溃的心情应该很多人都体会过,特别是本来不用迟到,但是堵车却能让你迟到上好几个小时。

在所有人都陷入绝望的时候,交警同志终于到达现场,开始疏散车辆。那些给我贴罚单的“讨厌”的人,一下子变成了无比高大的存在。 此时已经是快要九点半了,快要两个小时的时间,我竟然只挪动了两米不到。

一刹那间,我终于体会到什么是垃圾回收机制,你能体会吗?使用java进行编程,但是从来没有去思考过这个问题的小伙伴们? 这个巨大的丁字路口,可以理解为内存,可以允许有限的车辆在里面通行。 当车辆不停地始驶入,就像是无数的线程都要放到内存中,需要被处理。终于,内存爆了。接下来的一幕就是内存溢出,停止工作。 那些已经被不会被使用的垃圾线程依然停留在内存当中,就好像横在我眼前的这个大卡车。(当然对我来说,除了我之外的所有的车辆都是垃圾,应该被回收掉) 这个时候,内心里有一个声音:如果有人能把它们带走就好了。 于是,交警来了,他就是java中的垃圾回收机制。他以极快的速度把所有停滞在内存当中的废弃线程快速的清除出去。 于是,终于,一切又开始高速的运转开来。

在java之前众多的编程语言,都是通过编程人员自己来清除内存中已经被废弃掉的无用线程或者对象,这样就使得程序员的精力过多的消耗在了系统上。如果系统自身可以完成这部分工作,程序员就能够更多的去关注业务本身而不是系统效率。 这样做的好处是解放程序的大脑,但是坏处也是显而易见的。 那就是系统提供的垃圾回收机制无法做到像人工操作一样,在第一时间就知道代码中的对象已经使用完毕,而立即清除。系统需要固定的时间和固定的方式来做这件事情。这也就是众所周知的Android系统总是在开始的非常流畅,但是在使用一段时间之后就变得缓慢异常。好在通过java的不断升级,java语言的维护团队对效率做了很大的优化。 但是,无论多么优秀的垃圾回收机制,依然无法像人一样第一时间对无用的内存占用进行清除。一件工具很难做到尽善尽美,就像hibernate一样,降低了程序员对复杂SQL书写的要求,但是却减慢了效率。
在开始详细介绍垃圾回收机制的工作原理之前,有一个小小的思维拓展。

我记得刚开始接触到java的时候,老师讲对象在内存中的存储时,总是告诉我,引用存储在栈中,而对象是存储在堆中。老实说,即使是几年之后,如此抽象的讲解依然让我无法理解java的底层工作到底是怎样的? 而所谓的栈,堆又到底是什么,根本没有一个解释能让人直观的理解程序在内存中到底是怎样进行工作的。

那么说一些我自己的理解。 众所周知,计算机所有的工作原理是建立在二进制上。所谓二进制课本上告诉我们是由1,0组成的一种进制,而原因是机器只能识别二进制。好吧,关于二进制其实也是云雾缭绕的存在,我现在特别不理解在课堂上老师怎么能如此官面的解释二进制。

我们输入指令,计算机要做的事情有两个,第一是识别这道指令,第二是执行这道指令。那么是否可想想象二进制的存储方式就是一种信息的表达,就是把1,0写在一个数组当中,而计算机通过阅读这一串1,0组成的机器码,了解了指令的内容。然后它处理完这道指令之后,又以1,0的方式反馈给我们,这种二进制的信息存储最终被翻译成了我们能够识别的文字,音乐,图像等等。
说到最后,二级制就是一种信息的存储方式罢了。

那么所谓的栈,是否可以理解为java虚拟机将内存中的某一块区域指定为栈,这块区域是通过1,0 的方式存储指令。这种指定本身也不是固定,也许下一次虚拟机指定了另外的地方。如此是否可以更好地理解所谓的栈和堆呢。不过是强行划分的内存区域,并且在这个区域中是按照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语言的一些简单理解,原创作品,欢迎关注同名微信订阅号:程序员与工匠。

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

初识java这个小姑娘(二)的更多相关文章

  1. 初识java这个小姑娘(一)

    忽然想起这样一个场景:那时我还是小学三年级的一个小学生,上课的铃声响起,文艺委员起头,大家开始胡乱的开始唱歌,"让我们荡起双桨,小船儿推开波浪",歌声在一片稚气中慢慢停止.我们的语 ...

  2. 初识java这个小姑娘(三)

    说烂了的面向对象 我要说的面向对象,其实是一个我自己都觉的有点恶心的东西. 它是java语言入门如此初级的一个概念.作为一个老鸟,你可以吐口水给我,我可以把它们擦干,但作为总结还得说一说. 因为对于一 ...

  3. 初识Java作业

    初识Java作业 一.    填空题 Java技术按照用途不同分为三大版本,分别是JavaSE.     javaEE       和JavaMe Java虚拟机就是一个虚拟的用于执行  .class ...

  4. 初识Java Java基础知识

    今天给大家带来的是初级Java基础部分的知识:包括初识Java.变量.常量.数据类型.运算符.各种选择结构.循环结构.数组等Java的基础语法部分!!!内容.步骤超详细,附有各种案例的源代码(可以直接 ...

  5. 初识Java

    Java是一种简单的.面向对象的.分布式的.解释的.安全的.可移植的.性能优异的多线程语言.它以极强的安全性.平台无关性.硬件结构无关性.语言简洁.面向对象的特点,在网络编程语言中占据了无可比拟的优势 ...

  6. 实战Java虚拟机之二“虚拟机的工作模式”

    今天开始实战Java虚拟机之二:“虚拟机的工作模式”. 总计有5个系列 实战Java虚拟机之一“堆溢出处理” 实战Java虚拟机之二“虚拟机的工作模式” 实战Java虚拟机之三“G1的新生代GC” 实 ...

  7. Java设计模式(二) 工厂方法模式

    本文介绍了工厂方法模式的概念,优缺点,实现方式,UML类图,并介绍了工厂方法(未)遵循的OOP原则 原创文章.同步自作者个人博客 http://www.jasongj.com/design_patte ...

  8. Java 验证码、二维码

    Java 验证码.二维码 资源 需要:   jelly-core-1.7.0.GA.jar网站:   http://lychie.github.io/products.html将下载下来的 jelly ...

  9. Java入门(二)——果然断更的都是要受惩罚的。。。

    断更了一个多月,阅读量立马从100+跌落至10-,虽说不是很看重这个,毕竟只是当这个是自己的学习笔记,但有人看,有人评论,有人认同和批评的感觉还是很巴适的,尤其以前有过却又被剥夺的,惨兮兮的. 好好写 ...

随机推荐

  1. 10大H5前端框架,让你开发不愁

    ![](http://upload-images.jianshu.io/upload_images/8373224-7903a1466f7b9722?imageMogr2/auto-orient/st ...

  2. linux makefile 编译多个.c文件 实例

    本例由 main.c  add.c sub.c add_sub.h 四个文件组成:编写Makefile执行程序 /******************************************* ...

  3. Linux CentOS7 安装 Qt 5.9.2

    Linux CentOS7 安装 Qt 5.9.2 参考链接 http://doc.qt.io/qt-5/linux.html sudo yum groupinstall "C Develo ...

  4. K - 迷宫问题 POJ - 3984

    定义一个二维数组: int maze[5][5] = { 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, ...

  5. Thinkphp5 常量设置问题

    楼主是之前使用了thinkphp3.2快两年了,很早就听说过thinkphp的版本已经到达5了. 不过鉴于早期的版本尚未完善,并没有立即开始学习.最近做一个项目,尝试一下新的知识. 但是在使用的时候, ...

  6. Android 开发笔记___RadioButton

    horizontal <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" and ...

  7. [译]ASP.NET Core 2.0 视图组件

    问题 如何在ASP.NET Core 2.0中使用视图组件? 答案 新建一个空项目,修改Startup类并添加MVC服务和中间件: public void ConfigureServices(ISer ...

  8. linux-rmdir

    linux-rmdir rmdir命令用于删除空目录,删除的目录的里面必须无任何东西,有点鸡肋的命令 从下面先建立了一个a文件夹. 命令: rmdir a,即可删除这个空目录,ls 就找不到这个文件夹 ...

  9. linux-mkdir

    mkdir mkdir : 可以用来创建目录,如果不加创建路径即在本路径下创建一个新的指定的目录,否则即在给出的路径下创建目录. 目录创建:目录名尽量见名知意,根据不同需要分层创建,尽量避免在同一目录 ...

  10. jQuery+ajax实现局部刷新

    在项目中,经常会用到ajax,比如实现局部刷新,比如需要前后端交互等,这里呢分享局部刷新的两种方法,主要用的是ajax里面的.load(),其他高级方法的使用以后再做详细笔记. 第一种: 当某几个页面 ...