前言

​ 由于上次线上full gc,让我这个没有机会实战接触jvm的人,尝到了一定的甜头,同时也觉得自己还有很多东西需要去实战并总结。这是一篇记录jvm配置参数,使用jvisualvm工具来让人对jvm更加熟悉的一篇文章。

jvm参数配置

​ 以jdk1.8为例 ,介绍jvm参数配置之前,先要知道Jvm内存模型。堆,方法区,栈,本地方法栈,程序计数器。如下:图1.0

图1.0

​ jdk1.8 将方法区中的运行时常量池移动到了堆中,类的元数据放到了本地内存。栈,本地方法栈,程序计数器为线程私有。所以jvm内存大小 = 堆的大小。而 堆的大小 = 年轻代 + 老年代;年轻代的大小 = from survivor区 + to survivor 区 + eden 区。

  1. jvm内存区域
eg:
-Xmx100m : jvm最大内存大小为100M
-Xms100m : jvm每次full gc后,jvm可用最大内存,也称初始jvm可用内存大小;建议设置和Xmx一样大小
-Xmn50m : 年轻代最大,而且初始可用内存大小为50m (设置了这个,-XX:NewSize=20M和-XX:MaxNewSize=20 就没必要设置了。设置年轻代大小的时候,建议用-Xmn50m)
-XX:NewSize=20M : 年轻代初始可用内存大小20M
-XX:MaxNewSize=50M : 年轻代最大可用内存大小为50M
-XX:NewRatio=4 : 设置年轻代可用内存大小和老年代的比值为4,年轻代:老年代=1:4 那么年轻代占jvm内存可用大小为1/5
-XX:SurvivorRatio=8 : 设置survivor与eden区的比值为8,年轻代中有两个survivor区,所以2个survivor : eden = 2:8 ,那么一个survivor区占年轻代1/10。整个年轻代可用内存大小为9/10
  1. GC日志打印
eg:
-Xloggc:log.gc : 记录gc日志在当前目录
-XX:+PrintGC : 输出GC日志
-XX:+PrintGCDetails : 输出GC详细信息
-XX:+PrintGCTimestamps : 输出GC日志,以时间戳的形式
-XX:+PrintGCDateStamps : 输出GC日志,以时间点的信息
-XX:+PrintHeapAtGC : 输出GC前后,堆栈信息
  1. jvm垃圾回收器

图2.0

年轻代:

Serial :串行年轻代垃圾收集器 单线程

ParNew : 并发年轻代垃圾收集器 多线程

Parallel Scavenge : 并行年轻代垃圾收集器 多cpu

老年代:

Serial old 相对于Serial的老年代

CMS 相对于ParNew的老年代 多线程

Parallel old 相当于Parallel Scavenge的。

下面是参考网上的,用来作为笔记

参数设置

eg:
吞吐量优先
-XX:+UseParallelGC : 年轻代使用 并行垃圾收集器
-XX:+UseParallelOldGC : 老年代使用 并行垃圾收集器
-XX:+ParallelGCThreads=20 并行的线程为20 建议最好是和处理器数目一样
-XX:+UseAdaptiveSizePolicy:设置此选项后,并行收集器会自动选择年轻代区大小和相应的Survivor区比例,以达到目标系统规定的最低相应时间或者收集频率等,此值建议使用并行收集器时,一直打开。 响应时间优先
-XX:+UseConcMarkSweepGC : 设置老年代并发收集
-XX:+UseParNewGC:设置年轻代为并行收集。可与CMS收集同时使用。JDK5.0以上,JVM会根据系统配置自行设置,所以无需再设置此值。
-XX:CMSFullGCsBeforeCompaction=5:由于并发收集器不对内存空间进行压缩、整理,所以运行一段时间以后会产生“碎片”,使得运行效率降低。此值设置运行多少次GC以后对内存空间进行压缩、整理。
-XX:+UseCMSCompactAtFullCollection:打开对年老代的压缩。可能会影响性能,但是可以消除碎片

实战

  1. 利用idea开发工具,设置如下jvm参数,如下:图3.0

图3.0
代码如下:

public class Test{
public static void main(String[] args) {
byte[] a = new byte[2*1024*1024];
byte[] b = new byte[2*1024*1024];
byte[] c = new byte[2*1024*1024];
byte[] d = new byte[2*1024*1024];
byte[] e = new byte[2*1024*1024];
byte[] f = new byte[2*1024*1024];
byte[] g = new byte[2*1024*1024];
byte[] h = new byte[2*1024*1024];
}
}

运行出现:

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space

查看该目录下的loggc.gc文件,我拿出部分出来分析一下

{Heap before GC invocations=2 (full 1):
PSYoungGen total 13824K, used 10729K [0x00000000ff100000, 0x0000000100000000, 0x0000000100000000)
eden space 12288K, 87% used [0x00000000ff100000,0x00000000ffb7a7b0,0x00000000ffd00000)
from space 1536K, 0% used [0x00000000ffe80000,0x00000000ffe80000,0x0000000100000000)
to space 1536K, 51% used [0x00000000ffd00000,0x00000000ffdc6030,0x00000000ffe80000)
ParOldGen total 5120K, used 4104K [0x00000000fec00000, 0x00000000ff100000, 0x00000000ff100000)
object space 5120K, 80% used [0x00000000fec00000,0x00000000ff002020,0x00000000ff100000)
Metaspace used 3469K, capacity 4496K, committed 4864K, reserved 1056768K
class space used 380K, capacity 388K, committed 512K, reserved 1048576K
2018-12-11T16:20:02.537+0800: 0.133: [Full GC (Ergonomics) [PSYoungGen: 10729K->4756K(13824K)] [ParOldGen: 4104K->4097K(5120K)] 14833K->8853K(18944K), [Metaspace: 3469K->3469K(1056768K)], 0.0050671 secs] [Times: user=0.00 sys=0.00, real=0.01 secs]
Heap after GC invocations=2 (full 1):
PSYoungGen total 13824K, used 4756K [0x00000000ff100000, 0x0000000100000000, 0x0000000100000000)
eden space 12288K, 38% used [0x00000000ff100000,0x00000000ff5a5238,0x00000000ffd00000)
from space 1536K, 0% used [0x00000000ffe80000,0x00000000ffe80000,0x0000000100000000)
to space 1536K, 0% used [0x00000000ffd00000,0x00000000ffd00000,0x00000000ffe80000)
ParOldGen total 5120K, used 4097K [0x00000000fec00000, 0x00000000ff100000, 0x00000000ff100000)
object space 5120K, 80% used [0x00000000fec00000,0x00000000ff0004f8,0x00000000ff100000)
Metaspace used 3469K, capacity 4496K, committed 4864K, reserved 1056768K
class space used 380K, capacity 388K, committed 512K, reserved 1048576K
}

先看Heap上的信息 再GC前heap上年轻代的内存可用大小为13824K,但是我设置的15M,这是为什么呢,因为年轻代的大小 = survivor + eden ;还有一块survivor要空着。所以PSYoungGen = eden space + from/to space = 12288K + 1536K = 13824K 老年代大小为5120K=5M,这个是没错的。

然后看下PrintGCDetials输出的详细的内容

2018-12-11T16:20:02.537+0800: 0.133: [Full GC (Ergonomics) [PSYoungGen: 10729K->4756K(13824K)] [ParOldGen: 4104K->4097K(5120K)] 14833K->8853K(18944K), [Metaspace: 3469K->3469K(1056768K)], 0.0050671 secs] [Times: user=0.00 sys=0.00, real=0.01 secs]

2018-12-11T16:20:02.537+0800: 0.133 时间戳

Full GC

[PSYoungGen: 10729K->4756K(13824K)] 年轻代已用内存10729K,经过这次full gc,年轻代已用4756K,说明回收了10729K-4756K=5973K

[ParOldGen: 4104K->4097K(5120K)] 老年代已用内存4104K,经过这次full gc,老年代已用4097 ,说明回收了4104K-4097K= 7K

14833K->8853K(18944K) 堆内已用内存14833K,经过这个full GC ,堆内已用内存8853K ,说明回收了14833K-8853K= 5980K 等与年轻代回收内存大小+老年代回收内存大小 5973K+7K=5980K

  1. 利用jvisualvm.exe进行代码监控

    这个是jdk自带的程序,打开jdk安装目录,点进去打开bin目录,下图4.0 是我的安装目录

图4.0

双击打开如 图5.0

图5.0
可以看到左上角是Java中的进程,可以用再cmd 下用jps 查看,其实是一样的 如下图6.0

图6.0

运行如下代码:

public class Test{
public static void main(String[] args) throws InterruptedException {
for (int i = 0; i < 8; i++) {
byte[] a = new byte[2*1024*1024];
Thread.sleep(2*1000); //有时间查看Test进程
}
}
}

jvisualvm捕捉到了该Test进程 如下图7.0

图7.0

可以看到该进程id和我设置的jvm参数配置

也可以查看相应的GC 如图8.0

图8.0

和对应的GC监控 如图9.0

图9.0

哈哈哈,算是写完了,补充了上一篇欠下的东西。上次多谢 不如隐茶去的提醒,我的博客图片资源全部挂了,后面才发现公司内网才能访问该图片资源。如果LZ的分享有用的话,还望点个推荐。有问题还望留言探讨。

jvm本地实战的更多相关文章

  1. JVM本地方法栈及native方法

    看到虚拟机栈和本地方法栈的区别的时候有点疑惑,因为本地方法栈为虚拟机的Native方法服务.以下转载一篇关于native方法的介绍: http://blog.csdn.net/wike163/arti ...

  2. 转载一篇必须超级好的JVM配置实战

    不管是YGC还是Full GC,GC过程中都会对导致程序运行中中断,正确的选择不同的GC策略,调整JVM.GC的参数,可以极大的减少由于GC工作,而导致的程序运行中断方面的问题,进而适当的提高Java ...

  3. Java生鲜电商平台-缓存架构实战

    Java生鲜电商平台-缓存架构实战 说明:在Java生鲜电商中,缓存起到了非常重要的作用,目前整个项目中才用的是redis做分布式缓存. 缓存集群 缓存集群存在的问题 1.热key 缓存集群中的某个k ...

  4. 【JVM进阶之路】十:JVM调优总结

    1.调优原则 JVM调优听起来很高大上,但是要认识到,JVM调优应该是Java性能优化的最后一颗子弹. 比较认可廖雪峰老师的观点,要认识到JVM调优不是常规手段,性能问题一般第一选择是优化程序,最后的 ...

  5. Android使用JNI(从java调用本地函数)

    当编写一个混合有本地C代码和Java的应用程序时,需要使用Java本地接口(JNI)作为连接桥梁.JNI作为一个软件层和API,允许使用本地代码调用Java对象的方法,同时也允许在Java方法中调用本 ...

  6. JVM核心知识体系(转http://www.cnblogs.com/wxdlut/p/10670871.html)

    1.问题 1.如何理解类文件结构布局? 2.如何应用类加载器的工作原理进行将应用辗转腾挪? 3.热部署与热替换有何区别,如何隔离类冲突? 4.JVM如何管理内存,有何内存淘汰机制? 5.JVM执行引擎 ...

  7. 第五章 JVM调优(待续)

    Java虚拟机内存模型 JVM内存分配参数 垃圾收集基础 常用调优案列和方法 实用JVM参数 实战JVM调优

  8. JVM 问题排查和性能优化常用的 JDK 工具

    JDK 提供了一系列用于监控.诊断 Java 进程的工具,它们在 JDK 安装目录的 bin 目录下,有 jps.jcmd.jstack.jinfo.jmap 等.其中jmc.jconsole.jvi ...

  9. 800+Java后端经典面试题,希望你找到自己理想的Offer呀~

    前言 在茫茫的互联网海洋中寻寻觅觅,我收藏了800+道Java经典面试题,分享给你们.建议大家收藏起来,在茶余饭后拿出来读一读,以备未雨绸缪之需.另外,面试题答案的话,我打算后面慢慢完善在github ...

随机推荐

  1. Java中eclipse与命令行向main函数传递参数

    我们知道main函数是java程序的入口,main函数的参数类型是String[]. 1.Eclipse中向main方法传递参数 例如: public class Mytest { public st ...

  2. Java注解之Retention、Documented、Target、Inherited介绍

    先看代码,后面一个个来解析: @Retention(RetentionPolicy.RUNTIME) @Target(value = {ElementType.METHOD, ElementType. ...

  3. MySQL— 基础

    目录 一.MySQL概述 二.下载安装 三.数据库操作 四.数据表操作 五.表内容操作 一.MySQL概述 MySQL是一个关系型数据库管理系统,由瑞典MySQL AB 公司开发,目前属于 Oracl ...

  4. 【转】Python之装饰器

    [转]Python之装饰器 本节内容 必要知识回顾 情景模拟 装饰器的概念及实现原理 回马枪(带参数的装饰器) 一. 必要知识回顾 在开始说装饰器之前,需要大家熟悉之前说过的相关知识点: 函数即“变量 ...

  5. Linux 获取设备树源文件(DTS)里描述的资源【转】

    转自:http://www.linuxidc.com/Linux/2013-07/86839.htm 转自:http://blog.sina.com.cn/s/blog_636a55070101mce ...

  6. ES系列四、ES6.3常用api之文档类api

    1.Index API: 创建并建立索引 PUT twitter/tweet/ { "user" : "kimchy", "post_date&quo ...

  7. IntelliJ IDEA 12:

    启动参数-server -Xms1024m -Xmx1024m -XX:NewSize=128m -XX:MaxNewSize=128m -XX:PermSize=128m -XX:MaxPermSi ...

  8. Android Studio gradle配置详解

    android gradle配置详解 AppExtension类及其属性 可能大部分人看到AppExtension类会感觉到非常的陌生,其实我们在app中的build.gradle中填写配置信息的时候 ...

  9. OneNET麒麟座应用开发之二:串口读取PM25传感器数据

    作为环境数据监测站首先要获取大气中可吸入颗粒物的数据.为了检测PM25数据,我们采用北京海联信为的HLPM025K3型号传感器,该传感器使用激光法测量PM25和PM10的数据. 该型传感器的检测对象如 ...

  10. 为什么在python中推荐使用多进程而不是多线程(转载)

    最近在看Python的多线程,经常我们会听到老手说:"Python下多线程是鸡肋,推荐使用多进程!",但是为什么这么说呢? 要知其然,更要知其所以然.所以有了下面的深入研究: GI ...