【JVM】--GC

why:

首先为什么有GC,这就要说到C/C++了,在写C或C++的时候,关于对象的创建,销毁都是由程序员控制的,这样,程序员的权利太大了,就容易产生一个问题:如果对象无用了,但程序员忘记了delete/free空间

(执行析构函数),则就会导致内存泄漏,从而累积导致内存溢出。

 Java为了避免此类事情发生,直接将垃圾回收的工作交给了JVM,让程序员更安心的做更重要的工作,虽然此

块内容无需程序员操作,但了解这块的内容还是很有必要的,因为了解后,当出现了问题,才有思路去追溯。

 what:

 先拿丹姐的一个图:因为这张图宏观概括了垃圾回收的所有内容。下面我再详细的分述一下。


1、垃圾回收,首先了解它回收的区域:


 白底部分是线程私有的,随着线程的销毁而销毁,所以不需要回收,灰色底部分是共享的,也就是垃圾回收的对象。我们先分别介绍一下:

程序计数器:

 它可以看做是当前线程所执行的字节码的行号指示器。比如多线程时,由于Java虚拟机的多线程是通过线程轮流切换并且分配处理器执行时间的方式来实现的,为了切换后能恢复到正确的执行位置,每条线程都需要有一个独立的程序计数器,各条线程之间计数器互不影响,独立存储,也就是线程私有的......

虚拟机栈:

 它也是线程私有的,生命周期与线程相同。虚拟机栈描述的是Java方法执行的内存模型:每个方法在执行的同时都会创建一个栈帧用于存储局部变量表、操作数栈、动态链接、方法出口等信息。每一个方法从调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中入栈到出栈的过程。

我们经常说到的堆栈中的栈,就是指虚拟机栈,或者说是虚拟机栈中局部变量表部分。

本地方法栈:

 本地方法栈与虚拟机栈所发挥的作用是非常相似的,它们之间的区别不过是虚拟机栈为虚拟机执行Java方法(也就是字节码)服务,而本地方法栈则为虚拟机使用到的Native方法服务。不同的虚拟机对它的实现不同,譬如Sun的HopSpot虚拟机直接就把它和虚拟机栈合二为一了。

堆:

 对于大多数应用来说,堆是Java虚拟机所管理的内存中最大的一块,也是垃圾收集器管理的主要区域。Java堆是被所有线程共享的一块内存区域,在虚拟机启动时创建。此内存区域的唯一目的就是存放对象实例,几乎所有的对象实例都在这里分配内存。但随着JIT编译器的发展与逃逸分析技术逐渐成熟等......所有对象都分配在堆上也渐渐变得不是那么绝对了。

方法区:

 方法区与堆一样,是各个线程共享的内存区域,用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。这块区域也被称为“永久代”

2、用什么回收——垃圾收集器


简单介绍:

1. Serial使用复制算法,这种垃圾回收器会阻塞其他所有工作线程。
2. ParNew 是Serial的并行版本,它进行垃圾回收时也会暂停其他的工作线程,和Serial的区别就是它使用多个线程并行回收。
3. Parallal Scavenge
 目的:达到一个可控制的吞吐量:可设置最大垃圾收集停顿时间-XX:MaxGCPauseMillis:越小,停顿时间少,但牺牲的是吞吐量和新生代空间换取的

 4. Serial Old是Serial的老年代版本,使用标记-整理算法,单线程收集,Stop-the-world。
 5. ParallelOld是Parallel Scavenge的老年代版本,标记-整理算法,使用多线程并行回收,Stop-the-world,

 6.CMS:


 这是CMS的处理过程,它采用的是标记-清除算法,初始标记和重新标记阶段还是要阻塞其它线程的,但并发标记和并发清除以及重置线程阶段是和用户线程并发的。CMS也是第一个并发执行的垃圾收集器。

 7.G1


 G1采用的是分代收集算法,且是第一个既能回收新生代也能回收老年代的垃圾收集器。它设定的新生代老年代是非连续的空间。

3、如何确定哪些空间需要回收——垃圾定位

引用计数法:

 给对象添加一个引用计数器,每当有一个地方引用,加一;当引用失效,减一;
任何时刻计数器为零的对象就是不可能再被使用的 
缺点:无法解决对象之间相互循环引用的问题——产生内存泄漏

可达性分析算法


 从GC Roots开始,能达到的即为存活的对象,无法到达的即需要回收。

可以作为GC Roots的对象有:
 虚拟机栈中引用的对象
 方法区中类静态属性引用的对象
 方法区中常量引用的对象
 本地方法栈中JNI(Native方法)引用的对象

4、如何回收——垃圾回收算法

标记-清除算法


缺点:

1、清除的内存比较分散,回收起来比较耗时。
2、清除之后存在大量的内存碎片。

复制算法


 由于每次回收都会将存活对象复制到另一块区域的连续空间上,一方面不会有内存碎片存在,没有内存碎片的存在,分配新的内存时只需要在连续的未使用区域移动堆顶指针,按序分配内存即可。
 实际上垃圾回收器使用这种算法回收年轻代时,并不是按照1:1划分内存的,而是将内存划分为一块Eden区和两块Survivor, Hotspot默认Eden:Suvivor-1:Survivor-2=8:1:1,分配内存时只使用Eden区和其中一块Survivor,GC时对Eden区和这块正在使用的Survivor进行回收,然后将存活的对像复制到另一块未使用的Survivor上。

标记-整理算法


 标记整理算法不将内存分为两块,它使用全部的内存,在垃圾回收时它将存活的对象移动的内存的一端,然后清理掉边界以外未使用的内存。这样相对复制算法是用时间换空间。

分代收集算法


以上就是我对JVM-GC的理解~~~








猜你喜欢

转载自blog.csdn.net/u012654963/article/details/79195393