小研究 - Java虚拟机垃圾收集器的性能分析与调节

垃圾收集器是Java虚拟机(JVM)的核心组成部分之一,对Java虚拟机的性能有非常重要的影响。本文将介绍GC的工作原理以及对象回收算法,重点介绍JVM的分段回收技术;剖析JVM自带的GC性能分析工具;阐述如何通过命令行参数调节GC的运行,提高 GC的效率。

目录

1  前 言

2  垃圾收集器(GC)

3  GC的性能分析

3.1  衡量 GC的主要性能指标

4  调整 GC的运行参数,提高GC性能

4.1  增大堆空间

4.2  调节Young分段和Old分段的比例

5  结束语


1  前 言

自Java平台,特别是Java2平台发布以来,已经有许多软件,特别是大型服务器软件采用Java平台进行开发和部署,比如Bea公司的 WebLogic、IBM公司的 WebSphere等。

Java的成功一方面是由于Java的跨平台性、开放性和完全面向对象特征,顺应了软件的发展方向,获得了软件厂商的广泛支持;另一方面,对于广大的开发人员来说,Java平台屏蔽了内存分配和回收的复杂性,把开发人员从繁重的内存管理中解脱出来,使开发人员专注于应用本身的逻辑处理,提高了程序开发的效率。

尽管Java平台的优点很多,应用也非常广泛,但是,不乏人们对Java应用的抱怨,这些抱怨主要来自两个方面,一是Java应用占用的内存太大,二是Java应用的性能低下。引起上述两个问题的原因可能是多方面,但是通常与JVM的垃圾收集器(GarbageCollector,GC)有密切的关系。本文接下去首先研究Sun公司的JVM(JavaHotspotVirtualMachine)的垃圾收集器,分析垃圾收集的原理和算法;然后阐述如何通过JVM的命令行参数调节GC的性能。

本文以J2SE1.4.1提供的JVM为基础介绍 GC,但是不介绍J2SE1.4.1新引入的两种 GC———并行收集器(Parellelcollector)和并发紧缩—标记收集器(Concurrentmark-sweepcollector),这两种收集器都是针对多个CPU和大尺寸堆(通常超过1G)的。

2  垃圾收集器(GC)

在Java中,程序员需要通过关键字new为每个对象申请内存空间,所有的对象都在堆(Heap)中分配空间,对象的回收是由GC决定和执行的。换句话说,内存的分配是由程序完成的,而内存的回收是有GC完成的。那么 GC如何判断一个对象是否需要回收呢?

在运行的应用程序中,一个对象如果没有其他任何对象指向,那么这个对象就是垃圾对象,GC就可以回收这个对象。

一个最直截了当的垃圾回收算法就是遍历所有可及的对象,所有剩下的就是垃圾对象。通常的垃圾收集算法有:标记—清除法、标记—紧缩法和拷贝法。

在前两种方法中,都需要首先标记出所有的垃圾对象,标记垃圾对象的方法一种是引用计数法(ReferenceCounting),引用计数为0的对象就是垃圾对象,这种方法对于循环引用无能为力;一种是从根对象出发(例如全局对象)遍历所有可及的对象,标记出可用的对象,剩下的就是垃圾对象。在标记出所有垃圾对象之后,标记—清除法将无用对象占用的堆空间放入空闲队伍;标记—紧缩法与标记—清除法相似,只不过需要对堆空间进行整理以消除内存碎片,堆整理非常慢。

拷贝法与前面两种方法不同,在这种方法中,整个堆被分成相等的两块。在任意时刻,只有其中的一块用于分配对象,另一块是空的。在垃圾回收时,用于分配对象的一块称为源块,空的一块称为目的块,所有从根对象出发可及的对象都从源块拷贝到目的块,在下一次垃圾回收时,源块和目的块互换。这种方法效率很高,而且不存在内存碎片,缺点是被分配的内存只有一半是可用的,一半是空闲的。

Sun公司提供的Java虚拟机采用的是另外一种方法,称为“分段”垃圾收集(GenerationalGarbageCollection)。这种方法是基于一个事实,绝大多数对象“存活”的时间很短。研究表明,在大多数程序中,绝大多数对象(超过95%)都是临时对象,存活的时间很短。

为了充分利用这个事实,提高 GC的效率,JVM 对堆的管理是“分段”进行的,每个分段分别保存着不同年龄阶段的对象,当有一个分段被分配完时,启动相应的垃圾收集器。

如图1所示,这是Sun的JVM堆分段划分示意图:

整个地址空间被分成两段,一个“Old”分段,用于保存已经存活时间较长的对象;一个“Young”分段,存活时间还不长的对象。Young分段由一个“Eden”空间和两个“Survivor”空间组成。Young分段采用拷贝法进行垃圾回收,通常称为“辅回收(minorcollection)”,它的作用范围仅仅是Young分段中的对象,速度快,效率高,发生的频率比较高;Old分段通过标记—紧缩法进行垃圾收集,通常称为“主回收(majorcollection)”,它的作用范围是整个堆空间中的所有对象,速度慢。在一个应用程序中,频繁发生的是辅回收。

整个地址空间被分成两段,一个“Old”分段,用于保存已经存活时间较长的对象;一个“Young”分段,存活时间还不长的对象。Young分段由一个“Eden”空间和两个“Survivor”空间组成。

Young分段采用拷贝法进行垃圾回收,通常称为“辅回收(minorcollection)”,它的作用范围仅仅是Young分段中的对象,速度快,效率高,发生的频率比较高;Old分段通过标记—紧缩法进行垃圾收集,通常称为“主回收(majorcollection)”,它的作用范围是整个堆空间中的所有对象,速度慢。在一个应用程序中,频繁发生的是辅回收。

3  GC的性能分析

3.1  衡量 GC的主要性能指标

衡量 GC的性能主要有两个指标———吞吐量(Throughout)和“暂停(Pause)”。吞吐量指应用程序运行一段较长的时间后,不用在GC上的时间占总时间的百分数,包括对象分配的时间。“暂停”是由于GC运行使得应用程序暂停运行。

不同的应用程序对这两个性能指标的要求可能不一样。比如,Web应用程序,比较注重吞吐量,对于 GC引起的“暂停”可能要求不高。但是如果对于Swing界面应用,则强调响应速度,就是说每次“暂停”时间不能太长。

3.2  性能分析的方法

JVM在运行过程中记录下许多有用的信息,包括 GC的详细信息,可以通过命令行参数使JVM 输出这些信息,这些信息是我们进行性能分析的依据。目前,许多性能分析工具都是以这些 信 息 为 基 础 的,例 如,免 费 的 PerfAnal、Sun 公 司 的 HeapAnalysisTool1.0.3(HAT)等。下面介绍通过命令行参数获得JVM的运行信息的方法。

-verbose:gc

输出每次垃圾回收前、后堆的大小以及持续的时间。如下是输出片断:

[GC12818K->12728K(13772K),0.0046039secs]
[FullGC12728K->6792K(13772K),0.1376320secs]

第一条记录表示辅回放,箭头前面表示垃圾回收之前已经分配的堆大小,箭头之后表示回收之后实际的堆大小,括号中表示JVM的总的堆大小,最后一项表示运行时间。第二条记录表示主回收。主回收持续的时间比辅回收要长的多。

-Xloggc:<filename>

获得每次垃圾回收的开始时间、回收前后堆的大小以及持续的时间,输出的信息写入filename指定的文件。如下是文件片断:

5.02112:[GC5812K->2187K(65088K),0.0161182secs]
5.84255:[GC6283K->2573K(65088K),0.0173578secs]

中括号之前的数字,表示每次垃圾回收开始的时间,括号中各数据的意义与上文介绍的相同。

-XX:+PrintGCDetails

输出 Young分段和Old分段垃圾回收前后各自的大小以及每次垃圾回收持续的时间。如下是输出片断:

[GC[DefNew:592K->64k(640K),0.0040581secs]7614k->7431K
(8848K),0.0043531]secs]

[FullGC[Tenured:7367K->6210K(8208K),0.1380240secs]7599K-
>6210K(8848K),0.1383776secs]

第一条 记 录 表 示 一 次 辅 回 收,DefNew 所 在 的 括 号 表 示Young分段的情况,总的Young分段为640K;第二条记录是主回收,Tenured所在的括号表示 Old分段的情况,总的 Old分段为8208K。

-XX:+PrintTenuringDistribution

输出在 Young分段上,各个年龄阶段的对象所占的字节数。如下是输出片断:

Desiredsurvivorsize32768bytes,newthreshold31(max31)

-age 1:  6288bytes, 6288total
Desiredsurvivorsize32768bytes,newthreshold31(max31)

-age 1:  3960bytes, 3960total

-age 2:  5448bytes, 9408total

年龄为age1的对象表示首次进入Survivor空间的对象,年龄为age2的对象表示首次从Survivor空间拷贝到另一个Survi-vor空间的对象,age3的对象表示在Survivor空间之前拷贝2次,age4的对象在Survivor拷贝3次,依次类推。

hreshold表示年龄大于这个数目的对象进入 Old分段,最大值为31,也就说,对象在Survivor之间最多只能拷贝30次,之后若还存活,就必须进入 Old分段。

-Xrunhprof

这个 参 数 在 冒 号 之 后 还 可 以 带 有 参 数,可 以 通 过java-Xrunhprof:help命令查看,通过这个参数可以输出相当丰富的信息,包括每个方法占用的运行时间、每个对象什么时候被分配、占用空间的大小。

4  调整 GC的运行参数,提高GC性能

4.1  增大堆空间

一般来说,在JVM 中,垃圾回收发生的频率与堆的大小成反比,因此,增加堆空间,有助于提高垃圾收集器的性能。我们可以通过命令行参数-Xms和-Xmx设置应用程序的初始堆大小和最大堆大小。为了提高内存空间的利用率,JVM在每次垃圾回收之后都要检查堆的空闲率,空闲率的范围是通过参数:-XX:MinHeapFreeRatio=<mininum> 和-XX:MaxHeap-FreeRatio=<maximun>设置的,如果空闲率低于 mininum,JVM就会增大堆,但不会超过-Xmx设置的大小;如果空闲率超过max-imun,JVM就会减小堆,但不会小于-Xms设置的大小。

以如 下 机 器 配 置 为 例:Celeron1.7G,256 兆 DDR,Win-dows2000Professional,jdk1.4.1,Tomcat4.1.12。在某次运行:

ava-Xms64M-client-jar-Duser.dir=″C:\Tomcat41″″C:\Tomcat41\bin
\bootstrap.jar″start

完全启动Tomcat需要进行21次辅回收,0次主回收;如果运行:

java-Xms2M-client-jar-Duser.dir=″C:\Tomcat41″″C:\Tomcat41\bin
\bootstrap.jar″start

则完全启动Tomcat需要进行169次辅回收,5次主回收。在 Windows环境下,JVM的缺省值如表1所示:

4.2  调节Young分段和Old分段的比例

对于一定大小的堆来说,增大Young分段,有利于减小辅回收发生的频率;反之,会使辅回收发生的频率增大。至于两种情况下,主回收发生的频率是否会有明显的变化,取决于应用程序中“长寿命”的对象数量。

命令行参数-XX:NewRatio=n,可以设置 Old分段与 Young分段之间的比例,比例越大,Old分段越大。

以上文所述及的机器配置为例,某次运行:

java-client-Xms12M-Xmx12m-XX:NewRatio=40-jar-Duser.
dir=″C:\Tomcat41″″C:\Tomcat41\bin\bootstrap.jar″start

完全启动Tomcat需要170次辅回收,0次主回收,向该服务器请求jsp页面(带有session对象),辅回收频率非常高,主回收频率也升高。如果运行:

java-client-Xms12M-Xmx12m-XX:NewRatio=2-jar-Duser.dir=″
C:\Tomcat41″″C:\Tomcat41\bin\bootstrap.jar″start

完全启动Tomcat需要21次辅回收,6次主回收,向该服务器请求jsp页面(带有session对象),主回收频率比前一种情况高得多,辅回收不再发生,甚至发生内存溢出。

产生上述情况的原因是Tomcat本身的“长寿命”对象并不多,但是,jsp运行起来后,保存客户端信息的“长寿命”对象增多,例如用户的session对象等。因此,对于“长寿命”对象比较多的应用程序,NewRatio值宜较大,增大Old分段;对于“长寿命”对象比较少的应用程序,NewRaito的值宜较小,增大Young分段。

至于Young分段的Survivor空间占 Young分段的比例,可以通过参数-XX:SurvivorRatio来设置,例如,-XX:SurvivorRatio=6设置survivor:eden为1:6,换句话说每个survivor的空间是 Young分段的八分之一。一般来说,Survivor空间不宜过大,因为,其中一个Survivor空间始终是空的。

在 Windows环境下,JVM的缺省值如表2所示。

上述实验数据针对不同配置的机器、操作系统和运行环境,可能有所不同。在应用中,需要根据实际要求和约束条件,反复试验和分析,才能得出最佳的参数配置。JVM的缺省参数,是针对小应用程序的,对于大型应用程序往往是不能够适应的。

5  结束语

虽然,JVM屏蔽了对象分配和回收的复杂性,但是并不是说开发人员可以对GC一无所知,因为GC对于应用程序的性能有着至关重要的影响,有些时候甚至成为应用程序的性能瓶颈。事实上,JVM本身提供分析 GC性能的多种途径,同时提供充足的参数用以调节GC的性能,在我们的简单实验中,这些参数对GC的性能有非常重要的影响。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/92175.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

C语言练习5(巩固提升)

C语言练习5 选择题 选择题 1&#xff0c;下面代码的结果是&#xff1a;( ) #include <stdio.h> #include <string.h> int main() {char arr[] { b, i, t };printf("%d\n", strlen(arr));return 0; }A.3 B.4 C.随机值 D.5 &#x1f4af;答案解析&#…

python3/pip3 SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed

环境&#xff1a; mac os 背景&#xff1a; 电脑之前安装的是python3.9 &#xff0c; 现在升级到python3.10。 从python官网下载macos版本的python3.10 pkg。 双击安装。 程序使用aiohttp访问ebay 。 出错&#xff1a; aiohttp.client_exceptions.ClientConnectorCertifi…

SpringBoot入门篇2 - 配置文件格式、多环境开发、配置文件分类

目录 1.配置文件格式&#xff08;3种&#xff09; 例&#xff1a;修改服务器端口。&#xff08;3种&#xff09; src/main/resources/application.properties server.port80 src/main/resources/application.yml&#xff08;主要用这种&#xff09; server:port: 80 src/m…

STTran: Spatial-Temporal Transformer for Dynamic Scene Graph Generation

文章目录 0 Abstract1 Introduction2 Related Work3 Method3.1 Transformer3.2 Relationship Representation3.3 Spatio-Temporal Transformer3.3.1 Spatial Encoder3.3.2 Frame Encoding3.3.3 Temporal Decoder 3.4 Loss Function3.5 Graph Generation Strategies 4 Experimen…

C++的静态栈以及有点鸡肋的array数组

目录 1.静态栈 1.举例展示 2.注意事项 2.array 1.静态栈 1.举例展示 1.我们想到栈&#xff0c;就会想到是一个数组来维护它的&#xff0c;并且一般由于不知道存储的多少内容&#xff0c;所以一般都是用动态数组不断的在堆上开辟新的空间。 但是C支持了一个新的语法就是静…

2. 两数相加(中等系列)

给你两个 非空 的链表&#xff0c;表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的&#xff0c;并且每个节点只能存储 一位 数字。 请你将两个数相加&#xff0c;并以相同形式返回一个表示和的链表。 你可以假设除了数字 0 之外&#xff0c;这两个数都不会以 0 …

芯讯通SIMCOM A7680C (4G Cat.1)AT指令测试 TCP通信过程

A7680C TCP通信 1、文档准备 去SIMCOM官网找到A7680C的AT指令集 AT指令官网 进入官网有这么多AT指令文件&#xff0c;只需要找到你需要用到的&#xff0c;这里我们用到了HTTP和TCP的&#xff0c;所以下载这两个即可。 2、串口助手 任意准备一个串口助手即可 这里我使用的是XC…

浏览器的事件循环

其实在我们电脑的操作系统中&#xff0c;每一个运行的程序都会由自己的进程&#xff08;可能是一个&#xff0c;也可能有多个&#xff09;&#xff0c;浏览器就是一个程序&#xff0c;它的运行在操作系统中&#xff0c;拥有一组自己的进程&#xff08;主进程&#xff0c;渲染进…

【springboot】Spring Cache缓存:

文章目录 一、导入Maven依赖&#xff1a;二、实现思路&#xff1a;三、代码开发&#xff1a; 一、导入Maven依赖&#xff1a; <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-cache</artifactId><…

Nacos集群

需要与Nginx配合。 这是使用三个Nacos来搭建集群。 创建mysql数据库nacos。 配置Nacos 进入nacos的conf目录&#xff0c;修改配置文件cluster.conf.example&#xff0c;重命名为cluster.conf。 在cluster.conf文件的最后加上&#xff1a; #it is ip #example 127.0.0.1:8…

postman接口参数化设置

为什么需要参数化&#xff1f; 我们在做接口测试的过程中&#xff0c;会遇到需要测试同一个接口使用不同的数据的情况&#xff0c;如果每次去一个个填写数据就太麻烦了&#xff0c;这时我们就需要用到接口参数化&#xff0c;我们把数据单独的存放在一个文件中管理&#xff0c;…

[好书推荐] 之 <趣化计算机底层技术>

趣化计算机底层技术 底层技术优势购买 底层技术 相信很多老铁跟我一样, 在深入了解底层技术的时候 — — 就很头大 很多书籍看上去跟一个 老学究 一样, 说的话不是我们这些小白看的懂得… 看不懂就会 打击我们的自信心我们就有可能找一堆理由去玩(理所应当地去玩的那一种, 反…

Redis使用

环境配置 代码实现 Java public CoursePublish getCoursePublishCache(Long courseId){//查询缓存Object jsonObj redisTemplate.opsForValue().get("course:" courseId);if(jsonObj!null){String jsonString jsonObj.toString();System.out.println("从缓…

微服务中间件--http客户端Feign

http客户端Feign http客户端Feigna.Feign替代RestTemplateb.自定义Feign的配置c.Feign的性能优化d.Feign的最佳实践分析e.Feign实现最佳实践(方式二) http客户端Feign a.Feign替代RestTemplate 以前利用RestTemplate发起远程调用的代码&#xff1a; String url "http:…

基于XGBoots预测A股大盘《上证指数》(代码+数据+一键可运行)

对AI炒股感兴趣的小伙伴可加WX&#xff1a;caihaihua057200&#xff08;备注&#xff1a;学校/公司名字方向&#xff09; 另外我还有些AI的应用可以一起研究&#xff08;我一直开源代码&#xff09; 1、引言 在这期内容中&#xff0c;我们回到AI预测股票&#xff0c;转而探索…

网络基础入门

认识协议 协议其实是一种约定 网络协议初识&#xff1a; 1.内核上以结构体形式呈现 2.操作系统要进行协议管理--先描述&#xff0c;在管理 3.协议的本质是软件&#xff0c;软件是可以分层的&#xff0c;&#xff08;联系C继承多态的知识 &#xff09; 可以参考 &#xff1…

2023/8/17总结

项目完善&#xff1a; 算法推荐 item-CF 算法推荐我主要写的是协同过滤算法&#xff0c;然后协同过滤算法分成俩种—— 基于用户的 user-CF 基于物品的 item-CF 因为害怕用户冷启动&#xff0c;和数据量的原因 我选择了 item-CF 主要思路是——根据用户的点赞列表&…

什么是JVM ?

目录 一、JVM 简介 1.1 JVM 发展史 1.Sun Classic VM 2.Exact VM 3.HotSpot VM 4.JRockit 5.J9 JVM 6.Taobao JVM&#xff08;国产研发&#xff09; 1.2 JVM 和《Java虚拟机规范》 二、 JVM 运行流程 JVM 执行流程 三、JVM 运行时数据区 3.1 堆&#xff08;线程共享…

86. 分隔链表(中等系列)

给你一个链表的头节点 head 和一个特定值 x &#xff0c;请你对链表进行分隔&#xff0c;使得所有 小于 x 的节点都出现在 大于或等于 x 的节点之前。 你应当 保留 两个分区中每个节点的初始相对位置。 示例 1&#xff1a; 输入&#xff1a;head [1,4,3,2,5,2], x 3 输出&…

wireshark 流量抓包例题重现

[TOC](这里写目录标题 wireshark抓包方法wireshark组成 wireshark例题 wireshark抓包方法 wireshark组成 wireshark的抓包组成为&#xff1a;分组列表、分组详情以及分组字节流。 上面这一栏想要显示&#xff0c;使用&#xff1a;CtrlF 我们先看一下最上侧的搜索栏可以使用的…
最新文章