我眼里JAVA中的GC(垃圾回收机制)

想要了解GC 我认为应该从什么是GC?哪些东西会被回收?怎么样回收?以及什么时候回收?

GC:(根据百度翻译):程序本身发现并收集无用的内存。它是一种自动内存管理形式,不需要程序员释放内存。

而java中为什么会有这种机制的存在呢?

    1.减少程序员的工作量,也就是你不用过于扔垃圾的问题

     2.更加安全,

    3.减少内存泄漏

哪些内存需要被回收呢?

        我们知道在JVM运行的时候会出现一片区域来管理内存。其中就包括程序计数器(Program Counter Register),虚拟机栈(VM Stack),方法栈(Native Method Stack),方法区以及堆。而GC回收的就是方法区和堆中的垃圾,因为这里面的内存分配和回收是动态的。

内存什么时候被回收?

在堆中的内存:

    要想知道什么时候什么时候回收就要先了解如何判断一个对象已经死去了?在这里引入一个概念可达性分析(Reachability Analysis

    可达性分析:所有生成的对象都是一个称为"GC Roots"的根的子树。从GC Roots开始向下搜索,搜索所经过的路径称为引用链(Reference Chain),当一个对象到GC Roots没有任何引用链可以到达时,就称这个对象是不可达的(不可引用的),也就是可以被GC回收了。

对于需要回收的对象我们大体上分为四类引用,根据引用类型的不同,GC回收时也会有不同的操作

强引用:Object obj = new Object obj();只要存在强引用:GC永远不会回收被引用

软引用:这里面的是一些可能还有用的对象,当系统快要溢出了才回收他们

弱引用:只要进行GC,他就会被回收

虚引用:一个对象有没有虚引用对它本身不构成影响。

在方法区中的内存:

        首先要知道方法区内有什么?方法区里面有方法,有常量,对于一些没有的类或者废弃的常量我们就可以对其进行回收。那什么样的常量才被称为废弃的常量呢?其实只要是没有对象引用的常量就可以放心的被回收了。而什么是没有用的类呢?第一,就是堆中已经没有这个类的任何实例了,二,加载这个类的的Classoader已经被收购了.三.该类对应的java.lang.Class对象没有任何地方引用

下面我写一下该如何回收。一共四种方法

1.标记-删除:就是把要回收的对象先标记一下,然后一起删除。但是这两步都很慢,会产生碎片

2.标记-整理:也是先把要回收的对象标记一下,然后让所有将要被回收的对象移动到内存的一端,然后直接清除端边界以外的内存

3.复制的方法:这个方法就是把内存按照容量分成两块,每次只用其中的一块,当这一块用完了,就把还活着的对象复制到另一块上,然后把原来的那一块空间全部回收,缺点就是内存会缩小到原来的一半

一些收集器

Serial收集器

单线程收集器,表示在它进行垃圾收集时,必须暂停其他所有的工作线程,直到它收集结束。"Stop The World".

ParNew收集器

实际就是Serial收集器的多线程版本。

  • 并发(Parallel):指多条垃圾收集线程并行工作,但此时用户线程仍然处于等待状态;
  • 并行(Concurrent):指用户线程与垃圾收集线程同时执行,用户程序在继续运行,而垃圾收集程序运行于另一个CPU上。

Parallel Scavenge收集器

该收集器比较关注吞吐量(Throughout)(CPU用于用户代码的时间与CPU总消耗时间的比值),保证吞吐量在一个可控的范围内。

CMS(Concurrent Mark Sweep)收集器

CMS收集器是一种以获得最短停顿时间为目标的收集器。

G1(Garbage First)收集器

从JDK1.7 Update 14之后的HotSpot虚拟机正式提供了商用的G1收集器,与其他收集器相比,它具有如下优点:并行与并发;分代收集;空间整合;可预测的停顿等。

内存分配

    什么叫做自动管理内存:就是给对象分配内存以及回收给对象分配的内存

对象优先在Eden分配

大多数情况下,对象在新生代Eden区分配。当Eden区没有足够的内存时,虚拟机将发起一次Minor GC。

  • Minor GC(新生代GC):指发生在新生代的垃圾收集动作,因为Java对象大多都具备朝生夕灭的特性,所以Minor GC发生的非常频繁。
  • Full GC/Major GC(老年代GC):指发生在老年代的GC,出现了Major GC,经常会伴随至少一次的Minor GC。

大对象直接进老年代

大对象是指需要大量连续内存空间的Java对象(例如很长的字符串以及数组)。

长期存活的对象将进入老年代

JVM为每个对象定义一个对象年龄计数器。

  • 如果对象在Eden出生并经历过第一次Minor GC后仍然存活,并且能够被Survivor容纳,则应该被移动到Survivor空间中,并且年龄对象设置为1;
  • 对象在Survivor区中每熬过一次Minor GC,年龄就会增加1岁,当它的年龄增加到一定程度(默认为15岁,可通过参数-XX:MaxTenuringThreshold设置),就会被晋升到老年代中。
  • 要注意的是:JVM并不是永远的要求对象的年龄必须达到MaxTenuringThreshold才能晋升老年代,如果在Survivor空间中相同年龄所有对象大小的总和大于Survivor空间的一般,年龄大于等于该年龄的对象就可以直接进入老年代,无需等到MaxTenuringThreshold中要求的年龄。

空间分配担保

  • 在发生Minor GC之前,虚拟机会先检查老年代最大可用的连续空间是否大于新生代所有对象总空间,如果这个条件成立,则进行Minor GC是安全的;
  • 如果不成立,则虚拟机会查看HandlePromotionFailure设置值是否允许担保失败。如果允许,则急促检查老年代最大可用连续空间是否大于历次晋升到老年代对象的平均大小,如果大于,将尝试着进行一次Minor GC,尽管它是有风险的;
  • 如果小于或者HandePromotionFailure设置为不允许冒险,则这时要改为进行一次Full GC.

    


猜你喜欢

转载自blog.csdn.net/Chen_leilei/article/details/79580481