前言

​ 由于上次线上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. swift 计算100000以内的 回文数

    ... { var rep = var aa = a repeat{ rep = rep * + aa % aa = aa / }) if(rep == a) { print("\(a)是回 ...

  2. 【tomcat】sessionId学习(未完待续)

    这里主要研究tomcat中session的管理方式以及sessionId的原理,下文将研究sessionid存到redis中以及基于redis实现session共享. 平时也就是了解session是基 ...

  3. 如何往linux上面上传东西

    在linux中rz 和 sz 命令允许开发板与主机通过串口进行传递文件了,下面我们就来简单的介绍一下rz 和 sz 命令的例子. rz,sz是Linux/Unix同Windows进行ZModem文件传 ...

  4. C++学习1-(C语言基础、VS快捷键)

    C语言基础复习 1.三码 正数: 3码合1 ,正数的反码/补码就是其本身 负数: 原码就是符号位加上真值的绝对值,即用第一位表示符号,其余位表示值 原码:11010101 负数的反码是在其原码的基础上 ...

  5. mysql系列三、mysql开启缓存、设置缓存大小、缓存过期机制

    一.开启缓存 mysql 开启查询缓存可以有两种方法来开启一种是使用set命令来进行开启,另一种是直接修改my.ini文件来直接设置都是非常的简单的哦. 开启缓存,设置缓存大小,具体实施如下: 1.修 ...

  6. C#使用RabbitMQ

    1. 说明 在企业应用系统领域,会面对不同系统之间的通信.集成与整合,尤其当面临异构系统时,这种分布式的调用与通信变得越发重要.其次,系统中一般会有很多对实时性要求不高的但是执行起来比较较耗时的地方, ...

  7. mysql锁表与不锁表设置主从复制的方法

    有时候MySQL主从同步不一致比较严重的时候,需要手动同步.先说说在锁表的情况下如何操作:以下是其简要过程 1.先对主库锁表FLUSH TABLES WITH READ LOCK; 2.备份数据mys ...

  8. spring aop的五种通知类型

    昨天在腾讯课堂看springboot的视频,老师随口提问,尼玛竟然回答错了.特此记录! 问题: Spring web项目如果程序启动时出现异常,调用的是aop中哪类通知? 正确答案是: 异常返回通知. ...

  9. Python-百度经纬度转高德经纬度

    import math def bdToGaoDe(lon,lat): """ 百度坐标转高德坐标 :param lon: :param lat: :return: &q ...

  10. discuz安装:mysqli_connect()不支持advice_mysqli_connect

    原文:http://blog.csdn.net/changzhi1990/article/details/40983247 php -m 输出: PHP Warning: PHP Startup: U ...