如何查看JVM使用的是什么垃圾收集器

文章目录

    • 一、背景分析
    • 二、查看垃圾收集器
    • 三、理解的偏差
    • 四、深挖 demo 代码
    • 五、总结


封面


一、背景分析

无论讨论对象的内存分配,还是讨论内存的回收策略或是算法,都需要明确指出是基于哪种垃圾收集器进行的讨论。所以,很自然地就想到这个问题:如何查看 JVM 使用了哪种垃圾收集器呢

 


二、查看垃圾收集器

方法有很多,可以通过jconsole、VisualVM等工具间接地查看垃圾收集器的版本,但是比较简单的方式还是使用命令。

 
在cmd中执行下面的命令:

java -XX:+PrintCommandLineFlags -version

然后输出了如下内容:
在这里插入图片描述
从图中可以看出:

  • JDK版本:1.8.0
  • JVM是64位的Server版本
  • 结合下一张图的 参数说明,可知使用的垃圾收集器是 :新生代(Parallel Scavenge),老年代(PS MarkSweep)。这是虚拟机Server模式下的默认值。

在这里插入图片描述
图片来源:《深入理解Java虚拟机:JVM高级特性与最佳实践》

下面看一下jconsole的截图:
jconsole
 
启动jconsole的方法也很简单,只需要在命令行中输入: jconsole ,就可以启动该工具。

 


三、理解的偏差

但是,后来看到这位大哥的文章:
https://www.cnblogs.com/grey-wolf/p/9217497.html

才发现自己的理解是有偏差的。为什么这么说呢?
因为我写了一个验证GC的小demo,发现打印出的日志信息如下:

HeapPSYoungGen      total 9216K, used 3378K [0x00000000ff600000, 0x0000000100000000, 0x0000000100000000)eden space 8192K, 41% used [0x00000000ff600000,0x00000000ff94c880,0x00000000ffe00000)from space 1024K, 0% used [0x00000000fff00000,0x00000000fff00000,0x0000000100000000)to   space 1024K, 0% used [0x00000000ffe00000,0x00000000ffe00000,0x00000000fff00000)ParOldGen       total 10240K, used 10239K [0x00000000fec00000, 0x00000000ff600000, 0x00000000ff600000)object space 10240K, 99% used [0x00000000fec00000,0x00000000ff5ffc10,0x00000000ff600000)Metaspace       used 3036K, capacity 4496K, committed 4864K, reserved 1056768Kclass space    used 328K, capacity 388K, committed 512K, reserved 1048576K

相关代码如下:

public class MemoryAllocationDemo {/*** VM:-verbose:gc -Xms20M -Xmx20M -Xmn10M -XX:+PrintGCDetails -XX:SurvivorRatio=8*/public static void main(String[] args) {//对象直接分配到老年代byte[] alloc = new byte[10239*1024];}
}

虚拟机参数如下:

-verbose:gc -Xms20M -Xmx20M -Xmn10M -XX:+PrintGCDetails -XX:SurvivorRatio=8

参数说明:

  • 新生代:10M
  • 老年代:10M
  • 初始堆内存和最大堆内存:20M
  • Eden和Survivor的比例是:8:1(即Eden是8M,单个survivor是1M)

据说在jdk8中,默认启用了 ParallelOldGC ,相关代码如下:

--- a/src/share/vm/runtime/arguments.cpp	Mon Jan 30 15:21:57 2012 +0100
+++ b/src/share/vm/runtime/arguments.cpp	Thu Feb 02 16:05:17 2012 -0800
@@ -1400,10 +1400,11 @@void Arguments::set_parallel_gc_flags() {assert(UseParallelGC || UseParallelOldGC, "Error");
-  // If parallel old was requested, automatically enable parallel scavenge.
-  if (UseParallelOldGC && !UseParallelGC && FLAG_IS_DEFAULT(UseParallelGC)) {
-    FLAG_SET_DEFAULT(UseParallelGC, true);
+  // Enable ParallelOld unless it was explicitly disabled (cmd line or rc file).
+  if (FLAG_IS_DEFAULT(UseParallelOldGC)) {
+    FLAG_SET_DEFAULT(UseParallelOldGC, true);}
+  FLAG_SET_DEFAULT(UseParallelGC, true);// If no heap maximum was requested explicitly, use some reasonable fraction// of the physical memory, up to a maximum of 1GB.

相关修改来源:

https://hg.openjdk.org/jdk8u/jdk8u/hotspot/rev/24cae3e4cbaa

在这里插入图片描述
出于好奇,我在虚拟机参数中增加了如下内容:

-XX:+UseParallelOldGC -XX:-UseParallelGC

参数说明:

  • 启用 ParallelOldGC
  • 同时禁用 ParallelGC

打印出来的堆信息如下:

HeapPSYoungGen      total 9216K, used 3544K [0x00000000ff600000, 0x0000000100000000, 0x0000000100000000)eden space 8192K, 43% used [0x00000000ff600000,0x00000000ff976108,0x00000000ffe00000)from space 1024K, 0% used [0x00000000fff00000,0x00000000fff00000,0x0000000100000000)to   space 1024K, 0% used [0x00000000ffe00000,0x00000000ffe00000,0x00000000fff00000)ParOldGen       total 10240K, used 10239K [0x00000000fec00000, 0x00000000ff600000, 0x00000000ff600000)object space 10240K, 99% used [0x00000000fec00000,0x00000000ff5ffc10,0x00000000ff600000)Metaspace       used 3312K, capacity 4496K, committed 4864K, reserved 1056768Kclass space    used 359K, capacity 388K, committed 512K, reserved 1048576K

可以看出,堆信息几乎一样。所以单纯从堆信息看,是无法区分到底是使用了哪种GC收集器。

使用表格比较下两者的区别:

参数新生代-垃圾收集器老年代-垃圾收集器Old-线程Old-算法
UseParallelOldGCParallel ScavengeParallel Old多线程标记整理
UseParallelGCParallel ScavengePS MarkSweep(即Serial Old单线程标记整理

吞吐量优先 的场景下,建议使用第一个垃圾收集器组合。

 
结论:既然jdk源码都说默认启用了 ParallelOldGC ,那就记住这个结论吧。

 


四、深挖 demo 代码

现在回过头聊一聊demo中的代码意图。
代码:

byte[] alloc = new byte[10239*1024];

是创建了一个大的数组。其中的数组元素的个数是:10239k
然后我们看到其全部放到了老年代中:

ParOldGen       total 10240K, used 10239K [0x00000000fec00000, 0x00000000ff600000, 0x00000000ff600000)object space 10240K, 99% used [0x00000000fec00000,0x00000000ff5ffc10,0x00000000ff600000)

这些数组元素占用的空间:10239k,所以可以看出每个数组元素占了1个byte(字节)。
 
那么,这里的对象为什么会直接进入了老年代了呢

首先,这里的byte数组是一个大对象,并且它需要一段连续的空间(因为是数组)。
其次,这个大对象的占用空间有点特殊,是 10239k,恰好比 10M1k

那么,新生代可以容纳得下它吗?
前面我们说过新生代的总大小是10M,但是因为这10M 包含了1个 8M 的Eden区,还有2个 1M 的 Survivor区,所以实际可用空间是 9M(即 9216K)。很显然 9216K 是小于 10239k 的。

那么接下来需要再检查下老年代空间是否足够。老年代的空间是 10M ,前面讲过这个值比 10239k 正好大 1k 。所以,老年代是能容纳下这些数据的,根据 内存的分配策略,大对象会直接进入老年代。

因为jdk1.8使用的是 Parallel Scavenge 收集器,所以下面的虚拟机参数是不生效的:

# 单位是byte,1048576=1024k=1M
-XX:PretenureSizeThreshold=1048576

 


五、总结

本文介绍了如何查看JVM使用的垃圾收集器。在网友的启示下,获知jdk1.8.0中默认使用的是 Parallel Scavenge + Parallel Old 收集器。通过修改虚拟机参数还得知:Parallel Scavenge+PS MarkSweepParallel Scavenge + Parallel Old 两种收集器的GC日志是一样的。

然后又通过代码验证了一下大对象的内存分配策略:了解了什么情况下大对象会直接进入老年代。

 


参考:

  • 《深入理解Java虚拟机:JVM高级特性与最佳实践(第2版)》

  • https://github.com/zlserver/jvm_code

  • https://gitee.com/tanglongan/understanding-the-jvm

  • https://github.com/TangBean/understanding-the-jvm/tree/master

 
 
 
 
 

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

脱敏技术!!!

什么是数据脱敏??? 数据脱敏(Data Masking)是一种数据安全技术,旨在通过预先设定的规则和算法,对原始数据中包含的敏感信息进行变形处理,使得这些信息在非生产环境(例如…

考研数学|汤家凤1800基础部分要做完吗?

我教你一个方法,保证让你高质量的做完1800基础部分,而且还不用把所有题目都做了 我当然不是教你如何投机取巧,投机取巧是考不了高分的,我教你的都是我在实际考研过程中实际运用到的方法! 其实这个方法也是我在二战的时…

C#手术麻醉系统源码 可对接HIS LIS PACS 医疗系统各类设备 医院手麻系统源码

C#手术麻醉系统源码 可对接HIS LIS PACS 医疗系统各类设备 手术麻醉信息管理系统主要还是为了手术室开发提供全面帮助的系统,其主要是由监护设备数据采集子系统和麻醉临床系统两个子部分组成。包括从手术申请到手术分配,再到术前访视、术中记录及术后…

面试题:Java虚拟机JVM的组成

1. 基础概念 JVM是什么 Java Virtual Machine Java程序的运行环境(java二进制字节码的运行环境) 好处: 一次编写,到处运行 自动内存管理,垃圾回收机制 JVM由哪些部分组成,运行流程是什么? …

C++从入门到精通——C++输入和输出

C输入和输出 前言一、C打印Hello World二、C输入&输出关于I/O流C输入&输出cout函数cin函数endl函数 三、C输入和输出的说明printf、scanf和cout、cin的区别cout函数和cin函数控制精度和宽度std命名空间的使用惯例 前言 C中的输入和输出主要通过标准库中的iostream类实…

Linux 入门及其基本指令(上)

目录 0 .引言 1. XShell 远程登录 Linux 1.1 云服务器 1.2. XShell 远程登陆 Linux 2. 详解 Linux 基本指令 2.1 ls 指令 2.2 pwd 指令 2.3 cd 指令 2.4 touch 指令 2.5 mkdir指令 2.6 rmdir指令 && rm 指令 0 .引言 如今,Linux 在服务器…

uniapp vue-cli项目配置devServer和outPutDir

上一次说了使用vue-cli创建uni-app项目,然后使用第三方工具开发打包,利用jekins发布等。 这一次我想解决以下问题: 1我想配置devServer供开发环境使用,这样也可以解决开发环境的跨域问题 2以前我的每个版本信息都配置在package…

黑群晖基于docker配置frp内网穿透

前言 我的黑群晖需要设置一下内网穿透来外地访问,虽然zerotier的p2p组网已经很不错了,但是这个毕竟有一定的局限性,比如我是ios的国区id就下载不了zerotier的app,组网不了 1.下载镜像 选择第一个镜像 2.映射文件 配置frpc.ini&a…

C 指向指针的指针

指向指针的指针是一种多级间接寻址的形式,或者说是一个指针链。通常,一个指针包含一个变量的地址。当我们定义一个指向指针的指针时,第一个指针包含了第二个指针的地址,第二个指针指向包含实际值的位置。 一个指向指针的指针变量…

常见6种开源协议比较

前言 常见的开源许可协议有6种是比较常见和广泛使用的,每种协议都有其特定的使用场景和约束条件。这6种分别是GPL, LGPL,MIT许可证, Apache许可证,BSD许可证和Mozilla Public License(MPL). 6种开源许可协议…

Redis 开源协议变更背后:开源软件与云计算巨头的竞争博弈

01 背景 在云计算的风潮下,开源软件的生态环境正在经历一场剧变。2024 年 3 月 20 日,这种变化在 Redis 身上得到了集中体现。Redis 商业公司 CEO Rowan Trollope 宣布,Redis 将从 BSD 3-Clause 许可证过渡到双重许可证模式,包括…

【Redis】Redisson实现分布式锁

Redisson是一个在Redis的基础上实现的Java驻内存数据网格(In-Memory Data Grid)。它不仅提供了一系列的分布式的Java常用对象,还提供了许多分布式服务,其中就包含了各种分布式锁的实现。 官网地址 GitHub地址 Redisson入门 1.引…

Nexus3 Docker 私有仓库

Nexus3 Docker 私有仓库 安装并部署 Nexus3 $ docker search nexus3$ docker pull sonatype/nexus3$ mkdir /home/tester/data/docker/nexus3/sonatype-work $ sudo chown -R 200 /home/tester/data/docker/nexus3/sonatype-work$ docker run -d --namenexus3 \ --restartalw…

面试题目--3.19

1.foo()和foo()之间有什么区别? 代表所有的warning忽略 2.什么是csrf攻击?如何防范? csrf,跨站请求伪造,攻击方伪装用户身份发送请求从而窃取信息或者破坏系统。 基本原理:用户访问a网站登录并生成了coo…

亲历中国智驾大战,吴新宙加入NVIDIA半年后首秀

‍作者 |张祥威 编辑 |德新 吴新宙近日现身NVIDIA GTC,这是其从小鹏汽车离开加入NVIDIA之后的首次公开亮相。 吴目前担任NVIDIA汽车事业部副总裁,全面负责NVIDIA的车载计算产品线DRIVE平台的产品定义以及工程落地工作。吴新宙最广为人知的经历&#xf…

3.28C++

复数类的实现&#xff0c;写出三种构造函数&#xff0c;算术运算符、关系运算符、逻辑运算符重载尝试实现自增、自减运算符的重载 #include <iostream> using namespace std; class Num {int rel; //实部int vir; //虚部 public:Num():rel(2),vir(1){}Num(int rel,…

深入解析RSA算法原理及其安全性机制

码到三十五 &#xff1a; 个人主页 心中有诗画&#xff0c;指尖舞代码&#xff0c;目光览世界&#xff0c;步履越千山&#xff0c;人间尽值得 ! 目录 一、RSA算法简介二、RSA算法原理2.1 背景与数学基础2.2 密钥生成2.3 加密过程2.4 解密过程 三、安全性考虑四、RSA的使用五、…

数据结构进阶篇 之 【二叉树链序存储】的整体实现讲解

封建迷信我嗤之以鼻&#xff0c;财神殿前我长跪不起 一、二叉树链式结构的实现 1.二叉树的创建 1.1 手动创建 1.2 前序递归创建 2.二叉树的遍历 2.1 前序&#xff0c;中序以及后序遍历概念 2.2 层序遍历概念 2.3 前序打印实现 2.4 中序打印实现 2.4 后序打印实现 2.…

SpringBoot项目启动成功,但是调用接口直接报NOT FOUND 404

问题描述 SpringBoot项目启动成功&#xff0c;但是调用接口直接报NOT FOUND 404 解决办法 启动类中ComponentScan(basePackages {“com.afclab”})中的扫包路径和项目路径不一样&#xff0c;导致扫不到Controller等组件&#xff0c;修改成和项目路径一样就可以解决&#xf…

MYSQL高阶语句(一)

目录 一、常用查询 1、order by 按关键字排序 1.升序排序 2.降序排序 3.结合where进行条件过滤再排序 4.多字段排序 2、区间判断及查询不重复记录 1. and / or 且与或的使用 2.嵌套、多条件使用 3.distinct 查询不重复记录 3、GROUP BY 对结果进行分组 4、Li…