垃圾回收基础

2020/01/21 Jvm

java垃圾收集基础知识(oracle官方文档),总结深入理解java虚拟机

目录

java垃圾收集基础知识(oracle官方文档)

1.与JVM性能相关的组件

在调整性能时,JVM有三个组件主要是关于优化的。

堆 主要是对象的数据存储。然后,此区域由启动时选择的垃圾收集器管理。

Garbage Collector 垃圾回收器

JIT Compiler JIT编译器

大多数调优选项都与调整堆大小和为您的情况选择最合适的垃圾收集器有关。 JIT编译器对性能也有很大影响,但很少需要使用较新版本的JVM进行调优。

2.性能基础知识

通常,在调优Java应用程序时,重点是两个主要目标之一:响应性或吞吐量

响应性:是指应用程序或系统对请求的数据进行响应的速度。 例子包括: 桌面UI响应事件的速度有多快 网站返回页面的速度有多快 返回数据库查询的速度有多快 对于专注于响应性的应用程序,大的暂停时间是不可接受的。重点是在短时间内做出回应。

吞吐量:吞吐量侧重于在特定时间段内最大化应用程序的工作量。 如何衡量吞吐量的示例包括: 在给定时间内完成的交易数量。 批处理程序可在一小时内完成的作业数。 可在一小时内完成的数据库查询数。 对于专注于吞吐量的应用程序,高暂停时间是可接受的 由于高吞吐量应用程序在较长时间内专注于基准测试,因此不需要考虑快速响应时间。

3.什么是自动垃圾收集?

自动垃圾收集是查看堆内存,识别正在使用哪些对象以及哪些对象未使用的过程,以及删除未使用的对象。 使用中的对象或引用的对象意味着程序的某些部分仍然维护指向该对象的指针。程序的任何部分都不再引用未使用的对象或未引用的对象。 因此可以回收未引用对象使用的内存。

在Java中,解除分配内存的过程由垃圾收集器自动处理。

基本过程:

第1步:标记

该过程的第一步称为标记。这是垃圾收集器识别哪些内存正在使用哪些内存不再使用。

A live object 代表存活的对象,也就是还有对象引用,用蓝色表示。

Unreferenced Objects 未引用的对象,用黄金色表示。

在在标记阶段需要扫描所有对象来进行确定是否引用,如果必须扫描系统中的所有对象,则这可能是非常耗时的过程。

第2步:正常删除

正常删除会删除未引用的对象,从而保留引用的对象和指向可用空间的指针。

内存分配器保存对可以分配新对象的可用空间块的引用。

步骤2a:使用压缩删除

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

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

4.为什么分代垃圾收集?

深入理解java虚拟机

3.5垃圾收集器

1.垃圾收集器的基础概念

垃圾收集器是内存回收的具体实现 上图如果两个收集器之间存在连线,说明它们可以搭配使用。

2.Serial收集器

a.单线程收集器

b.进行垃圾收集时,必须暂停其他所有的工作线程,直到它收集结束。

c.新生代采取复制算法,暂停所有用户线程。老年代采用标记-整理算法,暂停所有用户线程。

d.从Serial到G1,用户线程的停顿时间在不断缩短,但是仍然没办法完全消除。

e.Serial并不是完全无用,它依然是虚拟机运行在Client模式下的默认新生代收集器。
它也有着优于其他收集器的地方:简单而高效,对于限定的单个CPU环境来说,Serial收集器由于没有线程交互的开销,专心做垃圾收集自然可以获得最高的单线程收集效率。
在用户的桌面应用场景中,分配给虚拟机管理的内存一般不会很大,收集几十兆甚至一两百兆的新生代,停顿时间完全可以控制在几十毫秒内最多一百毫秒内,只要是不频繁发生,这点停顿完全是可以接受的。

3.ParNew收集器

a.ParNew收集器其实就是Serial收集器的多线程版本,除了使用多线程进行垃圾收集之外,其余基本行为包括Serial收集器可用的所有控制参数。。。。。都与Serial收集器一样。

b.运行在Server模式下的虚拟机中首选的新生代收集器。

c.目前只有ParNew收集器能与CMS收集器配合工作。CMS是划时代的收集器,是第一款真正意义上的并发收集器,它第一次实现了让垃圾收集线程与用户线程基本同时工作

d.ParNew使用-XX:+UseConcMarkSweepGC选项后的默认新生代收集器,也可以使用-XX:+UseParNewGC选项来强制指定它。

e.可以使用-XX:ParallelGCThreads参数来限制垃圾收集的线程数。

4.并发和并行概念

后面会接触到几款并发和并行的收集器,并发和并行是两个概念:

并行(Paraller):指多条垃圾收集线程并行工作,但此时用户线程仍然处于等待状态。

并发(Concurrent):指用户线程和垃圾收集线程同时执行,但不一定是并行的,可能会交替执行,用户程序仍在继续执行,而垃圾收集程序运行与另一个CPU上。

5.Parallel Scavenge收集器

a.新生代收集器,采用复制算法,又是并行的多线程收集器。

b.它的关注点与其他收集器不同,CMS关注点是尽可能缩短垃圾收集时用户线程停顿时间,而Paraller收集器的目的则是达到一个可控制的吞吐量。

c.吞吐量是CPU用于运行用户代码的时间与CPU总消耗时间的比值。即吞吐量=运行用户代码时间 / (运行 用户代码时间+垃圾收集时间)

d.高吞吐量可以高效地利用CPU时间,尽快完成程序运算任务,主要适合在后台运算而不需要太多交互的任务。

e.停顿时间越短就越适合需要与用户交互的程序,良好的响应速度能提升用户体验。

f.Parallel Scavenge 用于精确控制吞吐量的两个参数:

  控制最大垃圾收集停顿时间的 -XX:MaxGCPauseMillis
   
  直接设置吞吐量大小的-XX:GCTimeRation参数
  
  MaxGCPauseMillis参数允许的值是一个大于0的毫秒数,收集器将尽可能地保证内存回收花费的时间不超过设定值。不要认为把这个参数的值设置小一点就能使系统的垃圾收集速度变得更快,GC停顿时间缩短是以牺牲吞吐量和新生代空间来换取的。
  GCTimeRation参数的值应当是一个大于0且小于100的整数,也就是垃圾收集时间占总时间的比率,相当于是吞吐量的倒数。如果把此参数设置为19,那允许的最大GC时间就占总时间的%5(即1/(1+19)),默认值为99,就是允许最大%1的垃圾收集时间。
  
g.Parallel Scavenge收集器也经常称为“吞吐量优先”收集器。

h.-XX:+UseAdaptiveSizePolicy 这是一个开关参数,打开后,不需要手工指定新生代的大小(-Xmn)、Edn与Survivor去的比例(-XX:SurvivorRatio)、晋升老年代对象大小(-XX:PretenureSizeThreshold)等细节参数了。虚拟机会根据当前系统的运行情况收集性能监控信息,动态调整这些参数以提供最合适的停顿时间或者最大的吞吐量,这种条件方式称为GC自适应的调节策略。

j.如果不了解优化,可以使用Parallel Scavenge收集器配合自适应调节策略。

6.Serial Old 收集器

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

b.也是给Client模式下的虚拟机使用。

c.如果在Server模式下使用,有两种用途,一种用途是在JDK1.5以及之前的版本中与Parallel Scavenge收集器使用。另一种是作为CMS收集器的后备预案。

7.Parallel Old收集器

1.是Parallel Scavenge收集器的老年代版本,使用多线程和“标记-整理”。

2.这个收集器是JDK1.6中才开始提供的。

3.在注重吞吐量以及CPU资源敏感的场合,都可以优先考虑Parallel  Scavenge加Parallel Old 收集器。

工作中调优实践

1.我们项目v2版本中jvm参数(未优化)

-Server启动

-Xms 初始堆大小

-Xmx 最大堆内存

-Xss 设置每个线程的堆栈大小

-XX:MetaspaceSize : JDK 1.7 和 1.8 将字符串常量由永久代转移到堆中,并且 JDK 1.8 中已经不存在永久代的结论 元空间的本质和永久代类似,都是对JVM规范中方法区的实现。不过元空间与永久代之间最大的区 别在于:元空间并不在虚拟机中,而是使用本地内存。因此,默认情况下,元空间的大小仅受本 地内存限制,但可以通过以下参数来指定元空间的大小: -XX:MetaspaceSize,初始空间大小,达到该值就会触发垃圾收集进行类型卸载,同时GC会对该值 进行调整:如果释放了大量的空间,就适当降低该值;如果释放了很少的空间,那么在不超过 MaxMetaspaceSize时,适当提高该值。 -XX:MaxMetaspaceSize,最大空间,默认是没有限制的。

-verbose:gc Java -verbose:gc 中参数-verbose:gc 表示输出虚拟机中GC的详细情况.

-Xloggc:gc.log -Xloggc:../logs/gc.log 日志文件的输出路径

-XX:+PrintGCDateStamps GC发生的时间信息

-XX:+PrintGCDetails 打印GC详细信息

Search

    Table of Contents