如何有效管理JVM中的垃圾?

前言

都说JVM是大牛们玩的技术,其实未必,如果面试官和你你谈到Java内存管理,那么首先,我建议你首先要了解Java垃圾收集的工作原理。 因为经常在运行JAVA应用程序时,大多数开发者是使用JVM自动帮你管理GC垃圾回收器(完全不关注,JVM自动完成回收),码农们只关注业务代码实现,不需要关注JVM是怎么管理的,对大家而言,更多人只知道程序正在运行中。但是老铁们,当你写的JAVA程序开始面临性能下降时,码农与架构师的区别就来了,所有的性能问题其实归根到底就是我们的GC回收效率变低了。

因此,让我们首先了解什么是JVM GC模型,然后,我们可以看到如何控制它并分析GC日志以查找应用程序中发生的任何差异。

一、什么是自动垃圾收集?

自动垃圾收集是指对堆内存的查看,并识别哪些对象正在使用哪些对象,以及删除未使用的对象的过程。

首先我们看一下自动GC垃圾收集,它的步骤如下:

1.标记(Marking)

该过程的第一步称为标记。其实就是垃圾收集器识别哪些内存正在使用,哪些内存不在使用的地方。

如果必须扫描系统中的所有对象,将是一个非常耗时的过程。

2.正常删除(Normal Deletion)

正常删除是指移除未引用的对象,留下引用的对象和指向空闲空间的指针。

3.压缩删除(Deletion with Compacting)

要进一步提高性能,除了删除未引用的对象外,还可以压缩剩余的引用对象。

通过将引用的对象移动到一起,这使得新的内存分配更加容易和快速。

二、全自动回收管理

当正在进行垃圾收集时,如果你的应用程序在该时间段内没有响应时,其实我们的期望是,GC应该花费最少的时间来回收它; 当然, 如果花费很多时间,则证明你的应用GC设置是有问题滴。

我们来看看下面的JVM内存模型,它分为不同的部分。JVM堆内存在物理上分为两部分 - Young Generation(新生代)和Old Generation(老年代)。

1.首先,将所有新的对象都分配给伊Eden space(伊甸园)。两个Survivor Space(幸存者区)都是空的。

2.当Eden space(伊甸园)填满时,会触发一个小的垃圾收集。

3.引用的对象被移动到第一个幸存者空间。清除Eden space(伊甸园)时,将删除未引用的对象。

4.下次要GC回收时,Eden space(伊甸园)空间也会发生同样的事情。删除未引用的对象,并将引用的对象移动到幸存者空间。但是,在这种情况下,它们被移动到第二个幸存者空间(S1)。

5.在较小的GC之后,当老化的对象达到一定的年龄阈值(在该示例中为8)时,它们从新生代晋升到老年代。

最终,将对老一代进行主要的GC回收,清理和压缩该空间。

三、如何在Java中调整垃圾收集的优化参数呢?

垃圾收集是指当JVM不再需要对象时,需要将它回收,释放内存。它包括查找不再使用的对象,释放与这些对象关联的内存,并偶尔压缩堆以防止内存碎片。

垃圾收集器使用一个或多个线程来执行回收工作。一般来说,为了完成跟踪对象引用及在内存中移动对象的工作,它需要确保应用程序线程当前没有使用这些对象,如果应用程序线程正在使用对象,GC回收时会导致对象的内存位置发生变化,可能发生不可预测的事情。这就是垃圾收集器在执行某些任务时必须暂停所有应用程序线程的原因。这些暂停有时被称为Stop-The-World暂停(吊炸天,全世界都被停止,哈哈)。

3.1调整堆大小

垃圾收集调优的第一步是**调整堆的大小。**这是因为如果堆太小,则会发生太多的GC回收回收内存次数,这会降低整体应用程序吞吐量。如果堆太大,那么GC回收次数会更少,但GC需要很长的时间,那么你的系统响应时间指标会受到影响。并行收集器特别容易受到堆大小的影响,因此如果你需要大的堆并且暂停时间较短,那么你应该尝试使用G1GC收集器。

**备注:**自从Java 9和Shenandoah垃圾收集器被视为还处于“实验性”阶段,不推荐使用并发标记扫描(CMS)收集器。但如果你正在运行在线交互式应用程序,那么系统会默认选择G1GC收集器,如果你正在运行脱机批处理应用程序,那么并行收集器应该是你的首选,这是我给大家的建议。

**堆的大小由两个值控制:**使用ms标志指定的初始值和使用mx标志指定的最大值。

-Xms1g -Xmx8g

堆的初始大小和最大大小,可以由JVM根据工作负载自动调整堆大小。如果JVM遇到内存压力并且观察到GC执行次数过多,它会不断增加堆,直到内存压力消失为止,或直到堆达到其最大值为止。如果内存压力很低,JVM还可以通过缩小堆大小来决定减少暂停时间。这个过程称为自适应大小调整**,**它不仅可以调整堆的整体大小,还可以调整年轻代和老代的大小和比例。

当然,如果你想调整GC行为和大小,**我建议你可以选择关闭自适应大小调整。**这可以节省JVM,这是计算堆大小所需的一小段时间。你可以通过将标志设置UseAdaptiveSizePolicy为false 来执行此操作。

-XX:-UseAdaptiveSizePolicy

此外,将初始堆大小设置为与最大堆大小相同的值,或将初始新生代大小设置为与最大新生代大小相同的值,这样操作可以有效地关闭自适应大小调整。

一般来说堆大小的最大设置准则就是**最大堆大小不应超过计算机上的物理内存量。**如果你运行多个JVM,则最大堆大小的总和不应超过计算机的物理内存。

3.2调整GC性能

在G1GC中,调整参数MaxGCPauseMillis执行以下所有优化,以尝试实现指定的暂停时间目标:

  • 调整堆的大小
  • 更快开始后台处理
  • 调整要提升为旧一代的对象的期限阈值
  • 调整混合GC循环期间处理的旧区域数

3.3修复并发模式失败

**G1GC是一个并发收集器。**这意味着当应用程序线程仍在运行时,垃圾收集进程的某些阶段可以并发运行。并且由于正在运行的应用程序可以继续产生垃圾,我们可能会遇到应用程序耗尽旧代内存而垃圾收集器仍在垃圾收集过程中的情况。也就是说,正在运行的应用程序生成的垃圾比它清理的速度快。**这种情况称为并发模式故障,**具体取决于故障发生的时间。如果您在GC日志中看到很多这些错误; 解决方案是增加堆的大小,更早地启动G1后台处理,或者通过使用更多后台线程来加速GC处理。

要更频繁地执行G1后台活动,您可以降低触发G1循环的阈值。这是通过减少InitiatingHeapOccupancyPercent标志的值来实现的。

-XX:InitiatingHeapOccupancyPercent=45

默认情况下,此标志设置为45。这意味着**当堆填充45%时会触发GC循环。**减少此值意味着GC会更早且更频繁地触发。但应注意的是,该值不会设置为太低而导致GC过于频繁发生的数字。

要增加后台线程数,请使用该ConcGCThreads标志。

-XX:ConcGCThreads=4

此标志的默认值设置为ParallelGCThreads加2 的值除以4.只要计算机上有足够的CPU可用,就可以增加此值而不会导致任何性能损失。

四、总结

如果调整堆大小并调整收集器对你不起作用,**那么你可以尝试另一个收集器。如果你仍然没有取得好成绩,那么你需要考虑调整应用程序代码本身的问题了,好了,写了这么多,希望对大家有帮助。

到此这篇关于如何有效管理JVM中的垃圾?的文章就介绍到这了,更多相关JVM垃圾管理内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 浅析JVM垃圾回收的过程

    JVM垃圾回收的算法很多,但是不管是哪种算法,在进行GC时大致的流程都是差不多的,主要有以下3个过程: 1. 枚举根节点 这个过程主要是找到所有的GC Roots对象,这些对象一般发生在JVM虚拟机栈栈帧.常量池中的静态对象.方法区中静态类属性引用.本地方法栈中引用的对象.这个过程会发生STW,所有的线程均运行到安全区域(Safe Region)才开始执行. 通常有两种算法: 引用计数法:每个对象中添加一个引用计数器,每当有一个地方引用它时,计数器值就+1:当引用失效时,计数器值就-1:任何时刻

  • JVM的垃圾回收机制详解和调优

    文章来源:matrix.org.cn 作者:ginger547 1.JVM的gc概述 gc即垃圾收集机制是指jvm用于释放那些不再使用的对象所占用的内存.java语言并不要求jvm有gc,也没有规定gc如何工作.不过常用的jvm都有gc,而且大多数gc都使用类似的算法管理内存和执行收集操作. 在充分理解了垃圾收集算法和执行过程后,才能有效的优化它的性能.有些垃圾收集专用于特殊的应用程序.比如,实时应用程序主要是为了避免垃圾收集中断,而大多数OLTP应用程序则注重整体效率.理解了应用程序的工作负荷

  • JVM垃圾回收原理解析

    概述 Java运行时区域中,程序计数器,虚拟机栈,本地方法栈三个区域随着线程的而生,随线程而死,这几个区域的内存分配和回收都具备确定性,不需要过多考虑回收问题.而Java堆和方法区则不一样,一个接口的多个实现类需要的内存不一样,一个方法的多个分支需要的内存可能也不一眼,我们只有在运行期,才能知道会创建的对象,这部分的内存分配和回收,是垃圾回收器所关注的.垃圾回收器需要完成三个问题:那些内存需要回收:什么时候回收以及如何回收. 那些垃圾需要回收 垃圾回收的基本思想是考察一个对象的可达性,即从根节点

  • JVM的7种垃圾回收器(小结)

    垃圾回收算法和垃圾回收器 对于JVM的垃圾回收算法有复制算法.标记清除.标记整理. 用阳哥的话就是:这些算法只是天上飞的理念,是一种方法论,但是真正的垃圾回收还需要有落地实现,所以垃圾回收器应运而生. JVM回收的区域包括方法区和堆,jvm对于不同区域不同的特点采用分代收集算法,比如因为所有的对象都是在Eden区进行分配,并且大部分对象的存活时间都不长,都是"朝生夕死"的,每次新生代存活的对象都不多,所以新采取复制算法:而jvm默认是新生代的对象熬过15次GC才能进入老年代,所以老年代

  • 浅谈jvm中的垃圾回收策略

    java和C#中的内存的分配和释放都是由虚拟机自动管理的,此前我已经介绍了CLR中GC的对象回收方式,是基于代的内存回收策略,其实在java中,JVM的对象回收策略也是基于分代的思想.这样做的目的就是为了提高垃圾 回收的性能,避免对堆中的所有对象进行检查时所带来的程序的响应的延迟,因为jvm执行GC时,会stop the word,即终止其它线程的运行,等回收完毕,才恢复其它线程的操作.基于分代的思想是:jvm在每一次执行垃圾收集器时,只是对一小部分内存 对象引用进行检查,这一小部分对象的生命周

  • 如何有效管理JVM中的垃圾?

    前言 都说JVM是大牛们玩的技术,其实未必,如果面试官和你你谈到Java内存管理,那么首先,我建议你首先要了解Java垃圾收集的工作原理. 因为经常在运行JAVA应用程序时,大多数开发者是使用JVM自动帮你管理GC垃圾回收器(完全不关注,JVM自动完成回收),码农们只关注业务代码实现,不需要关注JVM是怎么管理的,对大家而言,更多人只知道程序正在运行中.但是老铁们,当你写的JAVA程序开始面临性能下降时,码农与架构师的区别就来了,所有的性能问题其实归根到底就是我们的GC回收效率变低了. 因此,让

  • 详解JVM中的本机内存跟踪

    1.概述 有没有想过为什么Java应用程序通过众所周知的-Xms和-Xmx调优标志消耗的内存比指定数量多得多?出于各种原因和可能的优化,JVM可以分配额外的本机内存.这些额外的分配最终会使消耗的内存超出-Xmx限制. 在本教程中,我们将列举JVM中的一些常见内存分配源,以及它们的大小调整标志,然后学习如何使用本机内存跟踪监视它们. 2.原生分配 堆通常是Java应用程序中最大的内存使用者,但还有其他人.除了堆之外,JVM还从本机内存中分配出一个相当大的块来维护类的元数据,应用程序代码,JIT生成

  • 快速理解Java垃圾回收和jvm中的stw

    Java中Stop-The-World机制简称STW,是在执行垃圾收集算法时,Java应用程序的其他所有线程都被挂起(除了垃圾收集帮助器之外).Java中一种全局暂停现象,全局停顿,所有Java代码停止,native代码可以执行,但不能与JVM交互:这些现象多半是由于gc引起. GC时的Stop the World(STW)是大家最大的敌人.但可能很多人还不清楚,除了GC,JVM下还会发生停顿现象. JVM里有一条特殊的线程--VM Threads,专门用来执行一些特殊的VM Operation

  • JVM中堆内存和栈内存的区别

    Java把内存分成两种,一种叫做栈内存,一种叫做堆内存 在函数中定义的一些基本类型的变量和对象的引用变量都是在函数的栈内存中分配.当在一段代码块中定义一个变量时,java就在栈中为这个变量分配内存空间,当超过变量的作用域后,java会自动释放掉为该变量分配的内存空间,该内存空间可以立刻被另作他用. 堆内存用于存放由new创建的对象和数组.在堆中分配的内存,由java虚拟机自动垃圾回收器来管理.在堆中产生了一个数组或者对象后,还可以在栈中定义一个特殊的变量,这个变量的取值等于数组或者对象在堆内存中

  • java中JVM中如何存取数据和相关信息详解

    前言: 我们每天都在编写Java代码,编译,执行.很多人已经知道Java源代码文件(.java后缀)会被Java编译器编译为字节码文件(.class后缀),然后由JVM中的类加载器加载各个类的字节码文件,加载完毕之后,交由JVM执行引擎执行. 那在整个程序执行过程中,JVM中怎么存取数据和相关信息呢? 事实上在JVM中是用一段空间来存储程序执行期间需要用到的数据和相关信息,这段空间一般被称作为Runtime Data Area(运行时数据区),也就是我们常说的JVM内存. 一.运行时数据区域包括

  • JVM中的GC初识

    目录 GC简介 何为GC 为何要学习GC GC垃圾对象判定 引用计数法 可达性分析法 常见GC算法分析 标记清除 标记复制 标记整理 分代回收 章节面试分析 GC简介 何为GC GC(Garbage Collection)称之为垃圾回收,是对内存中的垃圾对象,采用一定的算法进行内存回收的一个动作.比方说,java中的垃圾回收会对内存中的对象进行遍历,对存活的对象进行标记,其未标记对象可认为是垃圾对象,然后基于特定算法进行回收. 为何要学习GC 深入理解GC的工作机制,可以帮你写出更好的Java应

  • Java 对象在 JVM 中的内存布局超详细解说

    目录 一.new 对象的几种说法 二.Java 对象在内存中的存在形式 1. 栈帧(Frame) 2. 对象在内存中的存在形式 ① 3. 对象中的方法存储在那儿? 4. Java 对象在内存中的存在形式 ② 三.类中属性详细说明 四.细小知识点 1. 如何创建对象 2. 如何访问属性 五.Exercise 六.总结 一.new 对象的几种说法 初学 Java 面向对象的时候,实例化对象的说法有很多种,我老是被这些说法给弄晕. public class Test { public static v

  • C#开发中的垃圾回收机制简析

    GC的前世与今生 虽然本文是以.NET作为目标来讲述GC,但是GC的概念并非才诞生不久.早在1958年,由鼎鼎大名的图林奖得主John McCarthy所实现的Lisp语言就已经提供了GC的功能,这是GC的第一次出现.Lisp的程序员认为内存管理太重要了,所以不能由程序员自己来管理.但后来的日子里Lisp却没有成气候,采用内存手动管理的语言占据了上风,以C为代表.出于同样的理由,不同的人却又不同的看法,C程序员认为内存管理太重要了,所以不能由系统来管理,并且讥笑Lisp程序慢如乌龟的运行速度.的

  • java基础学习JVM中GC的算法

    在java学习到JVM时候,总会很多朋友问到关于GC算法的问题,小编在此给大家整理关于JVM中GC算法的原理以及图文详细分析,希望能够帮助你对这个GC算法的理解. JVM内存组成结构: (1)堆 所有通过new创建的对象都是在堆中分配内存,其大小可以通过-Xmx和-Xms来控制,堆被划分为新生代和旧生代,新生代又被进一步划分为Eden和Survivor区.Survivor被划分为from space 和 to space组成,结构图如下: (2)栈 每个线程 执行每个方法的时候都会在栈中申请一个

随机推荐