jvm的垃圾回收机制——jvm的保洁工作

来源:互联网 发布:淘宝无线店铺视频教程 编辑:程序博客网 时间:2024/04/27 16:41

 jvm的保洁啊姐一早就来了,但让保洁阿姐犯愁的事情是:

   一:哪些东西需要回收呢?

   二:什么时候回收呢?

   三:用什么方式回收呢?

那我们先弄清上面疑问前,先了解一下jvm的内存分配

jvm 内存可以分栈,本地方法栈,程序计数器、堆和方法区;

栈 :  线程私有,生命周期和线程同步;存放局部变量(基本数据类型,对象的引用),其所需内存大小编译器时候    已经确认,故内存分配有确定性;

程序计数器: 线程私有,来获取线程下一条执行指令的字节码;

本地方法栈:执行native服务

堆:线程共享内存,动态分配;几乎所有的对象实例都在这里分配内存;管理内存最大的一块;

方法区:线程共享内存,用于存放已经被加载的类的信息;常量;静态变量及编译后 的代码等数据;

了解上面jvm内存分配后,那我们就可以回答第一个问题:

      总结如下:程序计算器、栈、本地方法栈3个区域的内存随着线程而生,随线程而灭;内存分配大体上在编译期间都已经确认;以此这些区域内存分配和回收都有确定性;故就不需要jvm的阿姐打理回收了;方法结束或线程结束时,内存自然跟着回收了。而堆和方法区是动态分配的,只有在程序运行期间才知道哪些对象要建,内存分配和回收是动态的;故jvm保洁阿姐只要关注此部分内存就好啦!!

      我们已经帮保洁阿姐处理了第一个疑惑;那下面我们帮处理第二个疑惑:什么时候回收呢?

      什么时候回收呢?其实很简单-----就是东西没有人用了,就可以回收了!那怎么判断东西有没有人再用呢?放在jvm中,假设对象没有线程或方法使用,标记此对象 “死翘翘了”,我们直要把死啦啦的对象回收就好了,现在就要只道哪些对象已经“死啦啦”呢?

    判断对象死啦啦的方法有下面几种:

      第一种算法——引用计数器算法 :给对象添加一个引用计数器,当有引用指向它的时候,计数器就加一;当引用失效时候;计数器就减一;任何计数器为0的时候,就不能再被引用了;此方法简单高效但有个缺点就是两个对象互相引用的时候;gc就没有办法回收此对象了;故很少采用此算法;

     第二种算法——  可达性分析算法 :目前主流算法,通过可达性分析来判断对象是否活着;其算法思想就是通过gc_root节点作为起始点,往下搜索,搜索走过的路径叫做引用链;当一个对象没有一个gc root相连的话,则证明此对象已经没有使用,可以判断可以回收;如下图:object 5,6,7没有GCroot相连,故在回收考虑范围内,但没有直接回收,因为此算法不仅要考虑是否可达,还要考虑另外一个条件;对象的flinalize的方法;其考虑如下:

   1  可达性分析 没有GCroot 相链的对象,再考虑其对象是否覆盖了object的flinalize()方法

       若没有----------直接回收

       若有————就把把这个对象放在fF-Queue队列,由一低优先级线程执行该队列中对象的finalize方法。执行finalize方法完毕后,GC会再次判断该对象是否可达,若不可达,则进行回收,否则,对象“复活”。所以这种方法对象可以自救哈;

  


总算把前两个疑惑解决了,现在解决第三个疑惑,用什么办法回收,现在垃圾收集算法下面几种算法:

 一:标记-清除算法    先标记好,然后统一回收;清除后产生零碎化内存;

二:复制算法   将可用内存划分为大小相等的两块,每次只使用一块,当这一块内存使用完后,就将还存活的对象复制到另外一块上;然后再把已经用过的内存一次清空;这样每次都对半个内存进行清空;内存分配的时候也不用考虑内存碎片,只要移动栈顶指针就好;压缩清除:为了提升性能,压缩清除会在删除没用的对象后,把所有存活的对象移到一起。这样可以提高分配新对象的效率。

三:分代收集算法 根据对象存活周期,分为新生代和老年代;针对不同的代采用不同的算法;在新生代中,每次垃圾回收时候,都会发现有大批对象死去,只有少量对象存活,就采用复制算法;只要复制少量的对象就能实现收集;而老生代中,对象存活率高,采用标记-清除方法



这里有五种可以在应用里使用的垃圾回收类型。仅需要使用JVM开关就可以在我们的应用里启用垃圾回收策略。让我们一起来逐一了解:

  1. Serial GC(-XX:+UseSerialGC):Serial GC使用简单的标记、清除、压缩方法对年轻代和年老代进行垃圾回收,即Minor GC和Major GC。Serial GC在client模式(客户端模式)很有用,比如在简单的独立应用和CPU配置较低的机器。这个模式对占有内存较少的应用很管用。
  2. Parallel GC(-XX:+UseParallelGC):除了会产生N个线程来进行年轻代的垃圾收集外,Parallel GC和Serial GC几乎一样。这里的N是系统CPU的核数。我们可以使用 -XX:ParallelGCThreads=n 这个JVM选项来控制线程数量。并行垃圾收集器也叫throughput收集器。因为它使用了多CPU加快垃圾回收性能。Parallel GC在进行年老代垃圾收集时使用单线程。
  3. Parallel Old GC(-XX:+UseParallelOldGC):和Parallel GC一样。不同之处,Parallel Old GC在年轻代垃圾收集和年老代垃圾回收时都使用多线程收集。
  4. 并发标记清除(CMS)收集器(-XX:+UseConcMarkSweepGC):CMS收集器也被称为短暂停顿并发收集器。它是对年老代进行垃圾收集的。CMS收集器通过多线程并发进行垃圾回收,尽量减少垃圾收集造成的停顿。CMS收集器对年轻代进行垃圾回收使用的算法和Parallel收集器一样。这个垃圾收集器适用于不能忍受长时间停顿要求快速响应的应用。可使用 -XX:ParallelCMSThreads=n JVM选项来限制CMS收集器的线程数量。
  5. G1垃圾收集器(-XX:+UseG1GC) G1(Garbage First):垃圾收集器是在Java 7后才可以使用的特性,它的长远目标时代替CMS收集器。G1收集器是一个并行的、并发的和增量式压缩短暂停顿的垃圾收集器。G1收集器和其他的收集器运行方式不一样,不区分年轻代和年老代空间。它把堆空间划分为多个大小相等的区域。当进行垃圾收集时,它会优先收集存活对象较少的区域,因此叫“Garbage First”。你可以在Oracle Garbage-FIrst收集器文档找到更多详细信息。

以上就是对jvm垃圾回收机制的简单分析;通过上面的分析可以解决了jvm保洁阿姐的三个困扰了;但新的问题又来了,比如一个例子就是;jvm保洁阿姐正在打扫,而你坐在旁边扔垃圾!一边打扫别人一边扔垃圾;这样怎么叫jvm保洁阿姐干活呀,若是我,直接辞职走人了哈哈哈;怎么解决这个问题,我们下一篇篇“ jvm 垃圾回收机制 安全点 ”博客一起学习吧;






原创粉丝点击