背景

生产环境有二台阿里云服务器,均为同一时期购买的,CPU、内存、硬盘等配置相同。具体配置如下:

节点

CPU

内存

硬盘

其它

A

2CPU

4G

普通云盘

Centos6.4 64位+JDK1.8.0_121

B

2CPU

4G

普通云盘

Centos6.4 64位+JDK1.8.0_121

由于这二服务器硬件和软件配置相同,并且运行相同的程序,所以在Nginx轮询策略均weight=1,即平台的某个流量由这二台机器平分。

有一次对系统进行例行检查,使用PinPoint查看下服务器”Heap Usage”的使用情况时,发现,在有一个系统Full GC非常频繁,大约五分钟一次Full GC(如果不明白Full GC的什么意思的,请自行百度),吓我一跳。这么频繁的Full GC,导致系统暂停处理业务,对系统的实时可用性大打折扣。我检查了一下Tomcat(Tomcat8.5.28)配置,发现在tomcat没有作任何关于JVM内存的设置,全部使用默认模式。由于这二服务器硬件和软件配置相同,并且运行相同的程序,所以在Nginx轮询策略均weight=1,即平台的某个流量由这二台机器平分。

GC数据

在业务峰期间,通过PinPoint观察的A、B节点的”Heap Usage”使用情况,分别进行以下几个时间段数据。

3小时图:

上图B系统在三个小时内,一共发生了22次Full GC,大约每8分钟进行一次Full GC。每次Full GC的时间大概有150ms左右,即B系统在三个小时内,大约有3300ms暂停系统运行。从上图来看,堆的空间最大值在890M左右,但在堆空间的大小大约200M就发生Full GC了,从系统资源的利用角度来考虑,这个使用率太低了。

上图A系统在3个小时内,一共发生了0次Full GC,嗯,就是没有任何停顿。 在这3小时,系统一直在处理业务,没有停顿。堆的总空间大约1536m,目前堆的空间大于500M。

6小时图:

上图B系统在6个小时的数据统计和3个小时很像,6个小时内一共发生了N次Full GC,均是堆的空间小于200M就发生Full GC了。

上图A系统在6个小时内,一共发生了0次Full GC,表现优秀。

12小时

上图B系统在12个小时内,一共发生了N次Full GC,左边Full GC比较少,是因为我们的业务主要集中白天,虽然晚上属于非业务高峰期间,还是有Full GC。

上图A系统在12个小时内,一共发生了0次Full GC,表现优秀。

GC日志

看下gc.log文件,因为我们两台服务器都输出了gc的详细日志,先看下B系统的Full GC日志。

上图全部是” [Full GC (Ergonomics)”日志,是因为已经去掉” GC (Allocation Failure”日志,这样更方便观察和分析日志,选取GC日志文件最后一条Full GC日志。

2018-12-24T15:52:11.402+0800: 447817.937: [Full GC (Ergonomics) [PSYoungGen: 480K->0K(20992K)] [ParOldGen: 89513K->69918K(89600K)] 89993K->69918K(110592K), [Metaspace: 50147K->50147K(1095680K)], 0.1519366 secs] [Times: user=0.21 sys=0.00, real=0.15 secs]

可以计算得到以下信息:

堆的大小:110592K=108M

老生代大小:89600K=87.5M

新生代大小:20992K=20.5M

分析:这次Full GC是因为老年代对象占用的空间的大小已经超过老年代容量 ([ParOldGen: 89513K->69918K(89600K)])引发的Full GC。是因为分配给老年代的空间太小,远远不能满足系统对业务的需要,导致老年代的空间常常被占满,老年代的空间满了,导致的Full GC。由于老年代的空间比较小,所以每次Full GC的时间也比较短。

A系统日志,只有2次Full GC,这2次GC均发生在系统启动时:

7.765: [Full GC (Metadata GC Threshold) [PSYoungGen: 18010K->0K(458752K)] [ParOldGen: 15142K->25311K(1048576K)] 33153K->25311K(1507328K), [Metaspace: 34084K->34084K(1081344K)], 0.0843090 secs] [Times: user=0.14 sys=0.00, real=0.08 secs]

可以得到以下信息:

堆的大小:1507328K=1472M

老生代大小:89600K=1024M

新生代大小:20992K=448M

分析:A系统只有系统启动才出现二次Full GC现象,而且是” Metadata GC Threshold”引起的,而不是堆空间引起的Full GC。虽然经过一个星期的观察,A系统没有Full GC,但一旦发生Full GC时间则会比较长。其它系统增加发现过,1024M的老年代,Full GC持续的时间大约是900ms秒。所以看得出来推也不是越大越好,或者说在UseParallelOldGC收集器中,堆的空间不是越大越好。

分析与优化

总体分析:

  1. B系统的Full GC过于频繁,是因为老生代只有约108M空间,根本无法满足系统在高峰时期的内存空间需求。由于ParOldGen(老年代)常常被耗尽,所以就发生Full GC事件了。
  2. A系统的堆初始空间(Xms)和堆的最大值(Xmx)均为1536m,完全可以满足业务高峰期的内存需求。

优化策略:

  1. B系统先增加堆空间大小,即通过设置Xms、 Xmx值增加堆空间。直接把Xms和Xmx均设置为1024M。直接堆的启动空间(Xms)直接设置为堆的最大值的原因是:因为直接把Xms设置为最大值(Xmx)可以避免JVM运行时不停的进行申请内存,而是直接在系统启动时就分配好了,从而提高系统的效率。把Xms(堆大小)设置为1024M,是因为采用JDK的建议,该建议通过命令得到” java -XX:+PrintCommandLineFlags -version” 。其中,“-XX:MaxHeapSize=1004719104”,即Xmx为1024M,其它建议暂时不采纳。所以综合下来的B系统的JVM参数设置如下:export JAVA_OPTS="-server –Xms1024m -Xmx1024m -XX:+UseParallelOldGC  -verbose:gc -Xloggc:../logs/gc.log  -XX:+PrintGCDetails -XX:+PrintGCTimeStamps"
  2. A系统JVM参数设置保持不变,以便观察系统运行情况,即:export JAVA_OPTS="-server -Xms1536m -Xmx1536m -XX:+UseParallelOldGC  -verbose:gc -Xloggc:../logs/gc.log  -XX:+PrintGCDetails -XX:+PrintGCTimeStamps"
  1. 将A、B节点系统的JVM参数采用2套参数,是为了验证A或B的参数更适合实际情况。

原文链接:https://my.oschina.net/u/3627055/blog/2995973

一次生产的JVM优化的更多相关文章

  1. 性能优化系列三:JVM优化

    一.几个基本概念 GCRoots对象都有哪些 所有正在运行的线程的栈上的引用变量.所有的全局变量.所有ClassLoader... 1.System Class.2.JNI Local3.JNI Gl ...

  2. JVM优化

    1.堆大小设置 JVM 中最大堆大小有三方面限制:相关操作系统的数据模型(32-bt还是64-bit)限制:系统的可用虚拟内存限制:系统的可用物理内存限制.32位系统下,一般限制在1.5G~2G:64 ...

  3. JVM 优化问题

    jvm 优化问题 JVM堆内存分为2块:Permanent Space 和 Heap Space. Permanent 即 持久代(Permanent Generation),主要存放的是Java类定 ...

  4. 给hive的metastore做JVM优化

    最近在测试环境下,hive的metastore不稳定,于是做一次JVM优化 在hive-env.sh中 export HADOOP_HOME=/opt/cdh/hadoop-2.6.0-cdh5.14 ...

  5. linux下jvm优化、tomcat调优

    系统环境:jdk1.8,apache-tomcat-8.5.35 一.jvm优化 进入 bin/catalina.sh,修改JAVA_OPTS配置: JAVA_OPTS="-server - ...

  6. 系统优化怎么做-JVM优化之VisualVM

    大家好,这里是「聊聊系统优化 」,并在下列地址同步更新 博客园:http://www.cnblogs.com/changsong/ 知乎专栏:https://zhuanlan.zhihu.com/yo ...

  7. (转)CentOS(5.8/6.4)linux生产环境若干优化实战

    CentOS(5.8/6.4)linux生产环境若干优化实战 原文:http://blog.51cto.com/oldboy/1336488 特别说明:本文来自老男孩linux培训VIP学生学习笔记. ...

  8. 多核服务器的JVM优化选项(转载)

    原文链接 现在多核CPU是主流.利用多核技术,可以有效发挥硬件的能力,提升吞吐量,对于Java程序,可以实现并发垃圾收集.但是Java利用多核技术也带来了一些问题,主要是多线程共享内存引起了.目前内存 ...

  9. JVM 优化之逃逸分析

    整理自 周志明<深入JVM> 1, 是JVM优化技术,它不是直接优化手段,而是为其它优化手段提供依据. 2,逃逸分析主要就是分析对象的动态作用域. 3,逃逸有两种:方法逃逸和线程逃逸.   ...

随机推荐

  1. Java线程的启动和停止(一)

    如何构造线程 在运行线程之前需要先构造线程对象,线程对象的构造需要指定线程所需要的属性,比如:所属线程组.线程优先级.是否为Daemon线程等信息.下面我们看一下,java.lang.Thread中对 ...

  2. input输入框只能输入数字和英文逗号

    <input type="text"  onkeyup="this.value=this.value.replace(/[^\d\,]/g,'')"> ...

  3. 【洛谷4251】 [SCOI2015]小凸玩矩阵(二分答案,二分图匹配)

    题面 传送门 Solution 看到什么最大值最小肯定二分啊. check直接跑一个二分图匹配就好了. orz ztl!!! 代码实现 /* mail: mleautomaton@foxmail.co ...

  4. Java后台开发精选知识图谱

    1.引言: 学习一个新的技术时,其实不在于跟着某个教程敲出了几行.几百行代码,这样你最多只能知其然而不知其所以然,进步缓慢且深度有限,最重要的是一开始就对整个学习路线有宏观.简洁的认识,确定大的学习方 ...

  5. 队列(Java实现)

    队列的特点是先进先出. 基于链表的队列 public class LinkedListQueue<Item> { private Node first; // 指向最早添加进队列的元素 p ...

  6. 包与类的命名 - service tool util 区别

    包与类的命名和定位时,service tool util 常常搞混淆,在此分析一下它们的定位: 名称 特点与定位 独立性 方法和类的属性 util 通用的.与业务无关的,可以独立出来,可供其他项目使用 ...

  7. JS高级_数据类型

    1.分类: a.基本(值)类型: * String :任意字符串 * Number :任意数字 * boolean : true/false * undefined :undefined * null ...

  8. Nginx之进程间的通信机制(共享内存、原子操作)

    1. 概述 Linux 提供了多种进程间传递消息的方式,如共享内存.套接字.管道.消息队列.信号等,而 Nginx 框架使用了 3 种传递消息的传递方式:共享内存.套接字.信号. 在进程间访问共享资源 ...

  9. Qt自定义窗口部件

    QtDesigner自定义窗口部件有两种方法:改进法(promotion)和插件法(plugin)   改进法   1.改进法之前,要先写好子类化QSpinBox后的HexspinBox.h和Hexs ...

  10. react 实现数据双向绑定

    好久没有更新了 只是都写在有道笔记中 今天整理下 一些基础的 大神勿喷 一个基础的不能再基础的数据双向绑定 因为react不同于vue 没有v-model指令 所以怎么实现呢? import Reac ...