Java虚拟机之垃圾回收

简述

Java与那些较传统的语言比如C++有个很大不同就是垃圾回收策略了。前者通常是虚拟机自动帮我们做了,而后者就需要我们手动来完成。
Java虚拟机帮我们完成了垃圾回收,是不是意味着我们就不用完全去管它了呢?当然不是的。在很多场景下,虚拟机默认做的并不能使我们满意。比如某个java应用较大时,频繁产生GC,就会非常影响我们应用的响应速度。这时候就需要我们根据自身需要,进行相应的调整。那么如何调整呢?这就需要我们对虚拟机的垃圾回收机制有所了解了。

找到将要回收的对象

如何找到要回收的对象呢?这里主要有两个算法:

引用计数法

算法大概思路就是给对象中添加一个引用计数器,每当一个地方引用它时,计数器值就加1;当引用失效时,计数器值就减1;任何时刻计数器值为0的对象就是不可能再被使用的。
但它的问题在于:很难解决对象之间相互引用的问题。比如对象A引用对象B,同时对象B又引用了对象A,但没有其他对象引用这两个对象,也就是说A和B这个整体是孤立的对象。按理说他们应该是被回收的,但是他们的计数器值并不为0,所以也就不能被回收了。

可达性分析算法

该算法主要思路就是通过一系列的称为“GC Roots”的对象作为起始点,从这些节点开始向下搜索,搜索所走的路径称为引用链(Refererce Chain),当一个对象到GC Roots没有任何引用链相连时,则证明此对象时不可用的。下图为例,即使对象5和对象6、7相连,但它到GC Roots是不可达的,所以对象5、6、7也是要被回收的。这里就解决了前面引用计数法所存在的那个问题。所以该算法目前也是大多数商用程序语言的主流实现。

垃圾收集算法

垃圾收集算法主要有以下四种,不过基本上后面都是前面的改进或者结合。

标记-清除算法

最基础的当数“标记-清除”(Mark-Sweep)算法了。算法分两个阶段:“标记”和“清除”。其中“标记”就是找到可以没有被引用的对象,“清除”就是收集该对象。如下图所示(图片凑合看下吧):

该算法的的缺点很明显:效率问题空间问题。前者是因为标记和清除两个过程效率都不高。后者是因为会产生大量不连续的内存碎片,从而导致后续需要分配大对象时找不到足够的连续空间而提前触发另一次收集动作。

复制算法

复制(Copying)算法主要时为了解决前面的效率问题。它将可用的容量分为大小相等的两块,每次只使用其中一块。其中一块快用完了,就将存活的对象复制到另外一块上,在把原来那块使用过的空间清理掉。如下图所示(颜色有点混了,格子中间水平分为相等的两部分)。
主要问题:浪费了太多内存。
目前多数商业虚拟机都采用该算法来回收新生代。但并不是严格按照1:1的比例分割内存,而是将它分为一块较大的Eden空间和两块较小的Survivor空间。一块Eden和一块Survivor比例大概为8:1 。每次使用Eden和一块Survivor空间,回收时将所有存活的对象复制到另外一块未使用的Survivor空间上。

标记-整理算法

标记-整理(Mark-Compact)算法,主要适用于对象存活率较高的情况,而前面的复制算法适用于存活率较低的情况。算法大概思路就是先标记要回收的对象,然后清除掉掉这些对象,最后将存活的对象复制整理到一起。也就是在前面标记-清除算法的基础上多了整理的步骤。

分代收集算法

分代收集(Generational Collection)算法主要是将内存划分为新生代老年代,不同块采用不同的算法。新生代对象存活率较低,就采用复制算法;老年代对象存活率较高,就采用标记-整理算法。

垃圾收集器


垃圾收集器就相当于前面介绍的那些算法的具体实现了。

新生代收集器使用的收集器:Serial、PraNew、Parallel Scavenge

老年代收集器使用的收集器:Serial Old、Parallel Old、CMS

Serial收集器(复制算法)

  新生代单线程收集器,标记和清理都是单线程,优点是简单高效。

Serial Old收集器(标记-整理算法)

  老年代单线程收集器,Serial收集器的老年代版本。

ParNew收集器(停止-复制算法) 

  新生代收集器,可以认为是Serial收集器的多线程版本,在多核CPU环境下有着比Serial更好的表现。

Parallel Scavenge收集器(停止-复制算法)

  并行收集器,追求高吞吐量,高效利用CPU。吞吐量一般为99%, 吞吐量= 用户线程时间/(用户线程时间+GC线程时间)。适合后台应用等对交互相应要求不高的场景。

Parallel Old收集器(停止-复制算法)

  Parallel Scavenge收集器的老年代版本,并行收集器,吞吐量优先

CMS(Concurrent Mark Sweep)收集器(标记-清理算法)

  高并发、低停顿,追求最短GC回收停顿时间,cpu占用比较高,响应时间快,停顿时间短,多核cpu 追求高响应时间的选择



引用:

《深入理解Java虚拟机》 第二版 周志明

原文地址:https://www.cnblogs.com/asche/p/11829301.html

时间: 2024-08-01 15:29:48

Java虚拟机之垃圾回收的相关文章

Java虚拟机之垃圾回收详解一

Java虚拟机之垃圾回收详解一 Java技术和JVM(Java虚拟机) 一.Java技术概述: Java是一门编程语言,是一种计算平台,是SUN公司于1995年首次发布.它是Java程序的技术基础,这些程序包括:实用程序.游戏.商业应用程序.在全世界范围内,Java运行在超过数十亿台个人计算机上,数十亿台设备上,还包括手机和电视设备.Java由一系列的关键组件作为一个整体构建出了Java平台. Java Runtime Edition 当你下载Java,你就得到了Java运行环境(JRE).JR

java虚拟机之垃圾回收算法

标记-清除算法: 这是最基础的,就是之前所讲的两次标记,首先标记出所有 需要回收的对象,然后进行统一清除, 这有两缺点:一是效率低,标记和清除(开启低优先级进行回收)都是低效率的.第二是空间问题,标记清除会产生大量的内存碎片. 复制算法: 可以将内存分为大小相等的两块,每次只使用一块,当一快内存使用完之后,将存活的对象移到另一块, 然后将使用过的一块用垃圾回收器将其回收掉. 这种方式运行简单,效率高.缺点是缩小了内存的实际使用大小. 比如使用20M的内存,每次都只能使用10M. 并且在对象存活

【深入理解Java虚拟机】垃圾回收机制

本文内容来源于<深入理解Java虚拟机>一书,非常推荐大家去看一下这本书. 本系列其他文章: [深入理解Java虚拟机]Java内存区域模型.对象创建过程.常见OOM 1.垃圾回收要解决的问题 垃圾收集(Garbage Collection,GC),要设计一个GC,需要考虑解决下面三件事情: (1)哪些内存需要回收? (2)什么时候回收? (3)如何回收? 哪些内存需要回收? 根据<Java内存区域模型.对象创建过程.常见OOM>中介绍的java内存模型,其中,程序计数器.虚拟机栈

实战java虚拟机(二)——垃圾回收算法

前言 垃圾回收是Java体系最重要的组成部分之一,和C/C++不同,Java虚拟机提供了全自动的内存管理方案,尽量减少了我们在内存资源管理方面的工作量,但是这套方案也并不完美,因此我们也需要深入学习垃圾回收的算法,在工作中遇到内存溢出等问题时也容易更快找到问题所在 一.引用计数法 引用计数法是最古老的垃圾收集算法,它的实现非常简单,只需要为每个对象配备一个整型计数器即可,当对象被引用时,计数器+1,引用失效时计数器-1. 显而易见,这种方式有着两个非常严重的问题: 1.无法处理循环引用,如果对象

JAVA虚拟机:垃圾回收策略及算法

java虚拟机中的程序计数器区.虚拟机栈区.本地方法栈区3个区域是随着线程的创建而创建,随着线程的结束而结束时,内存自然得到回收,所以这三个区域不需要过多考虑内存的回收问题. java虚拟机中的方法区和虚拟机堆区2个区是所有线程共享的区域,不同的接口或类需要的内存不同,且方法区和堆区往往是在程序运行期间进行内存动态分配或回收.GC回收器的使用范围就是对这两个区域的定义. 虚拟机堆区垃圾回收策略:GC回收器在回收内存之前,首先要知道哪些对象可以回收,即“死去”的对象是可以回收的:哪些对象不能回收,

java虚拟机的垃圾回收机制原理

1.常用的算法: a.引用计数法:为每一个对象配置一个整形计数器,当有一个引用时,计数器+1,引用失效时,计数器-1.计数器为0,进行垃圾回收 存在的问题:A对象引用B,B对象引用A.循环引用,无法清除,引起内存泄漏 java的垃圾回收器没有使用该算法 b.标记-清除算法 分标记阶段和清除阶段. 存在问题:释放后的空间不是连续的.内存分配不连续的空间,工作效率较低 c.复制算法 将内存空间分为两块,每次只使用其中一块,垃圾回收时,将正在使用的内存中存活的对象复制到未使用的内存中,然后,清除使用的

《深入理解JAVA虚拟机》垃圾回收时为什么会停顿

停顿现象 很多网上资料都会说到JAVA语言的一个劣势就是垃圾搜集时,整个进程会停顿. 到底是不是呢? 答案是确实存在. 为什么会停顿 垃圾收集的一个前提是要判断进程中的对象哪些是垃圾内存,哪些不是. 怎么判断呢,JVM里面使用了一种叫可达性分析的技术来枚举根节点. 一言以蔽之,JVM的内存空间里的若干对象都会有联系,形成树结构,如果一个对象通过寻路,能够找到根节点,那么这个对象就是活的,不能回收,否则就要回收. 在这个可达性分析过程中,是必须要求分析过程中树结构是不变的,也就是一致的.这意味着这

【java虚拟机序列】java中的垃圾回收与内存分配策略

在[java虚拟机系列]java虚拟机系列之JVM总述中我们已经详细讲解过java中的内存模型,了解了关于JVM中内存管理的基本知识,接下来本博客将带领大家了解java中的垃圾回收与内存分配策略. 垃圾回收(Garbage Collection,GC)是java语言的一大特色,在Java中,程序员不需要去关心内存动态分配和垃圾回收的问题,这一切都交给了JVM来处理.而在C/C++中是需要程序员主动释放的,而在java中则交给JVM自动完成,既然是交给程序自动执行,那么这里就必须完成以下几件事:

Java GC(垃圾回收)机制知识总结

目录 Java GC系列 Java系列笔记(3) - Java 内存区域和GC机制 面试题:"你能不能谈谈,java GC是在什么时候,对什么东西,做了什么事情?" Java GC系列 本部分来自Java GC系列(1):Java垃圾回收简介 Java的内存分配与回收全部由JVM垃圾回收进程自动完成.与C语言不同,Java开发者不需要自己编写代码实现垃圾回收.这是Java深受大家欢迎的众多特性之一,能够帮助程序员更好地编写Java程序. 下面四篇教程是了解Java 垃圾回收(GC)的基