JVM调优方法

调优前的规划

基础概念

什么是调优

  1. 根据需求进行JVM规划和预调优
  2. 优化运行JVM运行环境(慢、卡顿)
  3. 解决JVM运行过程中出现的各种问题(OOM

调优的目的

  1. 吞吐量优先:用户代码时间 /(用户代码执行时间 + 垃圾回收时间);
  2. 响应时间优先:STW越短,响应时间越短。

所谓调优,首先确定追求的什么,是吞吐量优先,还是响应时间优先?还是在满足一定的响应时间的情况下,要求达到多大的吞吐量?

对于科学计算,吞吐量,数据挖掘,thrput,采用吞吐量优先(PS + PO

对于互联网应用,采用响应时间优先(CMS,G1

调优步骤

  1. 熟悉业务场景(没有最好的垃圾回收器,只有最合适的垃圾回收器)
    1. 响应时间、停顿时间 [CMS G1 ZGC] (需要给用户作响应)
    2. 吞吐量 = 用户时间 /( 用户时间 + GC时间) [PS]
  2. 选择回收器组合
  3. 计算内存需求(物理内存1/4~1/2)
  4. 选定CPU(越高越好)
  5. 设定年代大小、升级年龄
  6. 设定日志参数
    1. -Xloggc:/opt/xxx/logs/xxx-xxx-gc-%t.log -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=5 -XX:GCLogFileSize=20M -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCCause
    2. 或者每天产生一个日志文件
  7. 观察日志情况

优化环境

  1. 有一个50万PV的资料类网站(从磁盘提取文档到内存)原服务器32位,1.5G的堆,用户反馈网站比较缓慢,因此公司决定升级,新的服务器为64位,16G的堆内存,结果用户反馈卡顿十分严重,反而比以前效率更低了

    • 为什么原网站慢?
      很多用户浏览数据,很多数据load到内存,内存不足,频繁GC,STW长,响应时间变慢

    • 为什么会更卡顿?
      内存越大,FGC时间越长

    • 怎么办?
      PS -> PN + CMS 或者 G1

  2. 系统CPU经常100%,如何调优?
    CPU100%那么一定有线程在占用系统资源

    1. 找出哪个进程cpu高(top
    2. 该进程中的哪个线程cpu高(top -Hp pid
    3. 导出该线程的堆栈 (jstack)
    4. 查找哪个方法(栈帧)消耗时间 (jstack)
    5. 工作线程占比高 | 垃圾回收线程占比高

    参考:https://www.cnblogs.com/zhuqq/p/5938187.html

  3. 系统内存飙高,如何查找问题?

    1. 导出堆内存 (jmap)
    2. 分析 (jhat jvisualvm mat jprofiler … )

    关于jmap参考:https://www.cnblogs.com/sxdcgaq8080/p/11089664.html

  4. 如何监控JVM

    1. jstat jvisualvm jprofiler arthas top…

各种名词

QPS

Queries Per Second,每秒查询数。每秒能够响应的查询次数。QPS是对一个特定的查询服务器在规定时间内所处理流量多少的衡量标准,在因特网上,作为域名系统服务器的机器的性能经常用每秒查询率来衡量。每秒的响应请求数,也即是最大吞吐能力

TPS

Transactions Per Second,每秒处理的事务数目。一个事务是指一个客户机向服务器发送请求然后服务器做出反应的过程。客户机在发送请求时开始计时,收到服务器响应后结束计时,以此来计算使用的时间和完成的事务个数,最终利用这些信息作出的评估分。

TPS 的过程包括:客户端请求服务端、服务端内部处理、服务端返回客户端。

例如,访问一个 Index 页面会请求服务器 3 次,包括一次 html,一次 css,一次 js,那么访问这一个页面就会产生一个“T”,产生三个“Q”。

PV

page view,即页面浏览量,通常是衡量一个网络新闻频道或网站甚至一条网络新闻的主要指标。

UV

Unique Visitor,指独立访客访问数,统计1天内访问某站点的用户数(以 cookie 为依据),一台终端为一个访客。

案例分析

测试代码:

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * 从数据库中读取信用数据,套用模型,并把结果进行记录和传输
 */

public class FullGC_Problem01 {

    private static class CardInfo {
        BigDecimal price = new BigDecimal(0.0);
        String name = "张三";
        int age = 5;
        Date birthdate = new Date();

        public void m() {}
    }

    private static ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(50,
            new ThreadPoolExecutor.DiscardOldestPolicy());

    public static void main(String[] args) throws Exception {
        executor.setMaximumPoolSize(50);

        for (;;){
            modelFit();
            Thread.sleep(100);
        }
    }

    private static void modelFit(){
        List<CardInfo> taskList = getAllCardInfo();
        taskList.forEach(info -> {
            // do something
            executor.scheduleWithFixedDelay(() -> {
                //do sth with info
                info.m();

            }, 2, 3, TimeUnit.SECONDS);
        });
    }

    private static List<CardInfo> getAllCardInfo(){
        List<CardInfo> taskList = new ArrayList<>();

        for (int i = 0; i < 100; i++) {
            CardInfo ci = new CardInfo();
            taskList.add(ci);
        }

        return taskList;
    }
}

java -Xms200M -Xmx200M -XX:+PrintGC top.tjtulong.jvm.gc.FullGC_Problem01运行程序

结果:内存不断增长,频繁FullGC,一段时间后OOM,发生了内存泄露。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LCSWjqKW-1587348441733)(http://picture.tjtulong.top/%E6%A1%88%E4%BE%8B%E4%B8%8D%E6%96%ADfullGC.jpg)]

一般是运维团队首先受到报警信息(CPU Memory);

top命令观察到问题:内存不断增长,CPU占用率居高不下;

top -Hp pid观察进程中的线程,哪个线程CPU和内存占比高;

jps用来定位具体java进程

jstack定位线程状况,检测死锁,重点关注:WAITING BLOCKED
eg. waiting on <0x0000000088ca3310> (a java.lang.Object)
假如有一个进程中100个线程,很多线程都在waiting on ,一定要找到是哪个线程持有这把锁怎么找?搜索jstack dump的信息,找 ,看哪个线程持有这把锁RUNNABLE。

p.s. 线程池的ThreadFactory要自定义名称,便于定位问题

jinfo pid:查看进程信息

jstat -gc pid 打印GC的情况

jstat -gc 4655 500 : 每个500个毫秒打印GC的情况

arthas观察 / jconsole / jvisualVM / Jprofiler(最好用)

不能用VisualVM图形化(内测用),dump更不行,会中断程序

jmap:可以查看某个类产生的对象,但如果堆特别大,会停掉线程。

  1. jmap - histo 4655 | head -20,查找有多少对象产生
  2. jmap -dump:format=b,file=xxx pid 导出堆快照

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nk9QYIZY-1587348441739)(http://picture.tjtulong.top/jmap.JPG)]

可以看到许多类的实例数量持续增长。

开启-XX:+HeapDumpOnOutOfMemoryError后,当出现OOM,后自动dump出堆快照。

jconsole远程连接

JConsole是一种基于JMX的可视化监视、管理工具可进行内存管理(jstat)、线程管理(jstack)、查看死锁等。

  1. 程序启动加入参数:

    java -Djava.rmi.server.hostname=192.168.17.11 -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=11111 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false XXX
    
  2. 如果遭遇 Local host name unknown:XXX的错误,修改/etc/hosts文件,把XXX加入进去

    192.168.17.11 basic localhost localhost.localdomain localhost4 localhost4.localdomain4
    ::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
    
  3. 关闭linux防火墙(实战中应该打开对应端口)

    service iptables stop
    chkconfig iptables off #永久关闭
    
  4. windows上打开 jconsole远程连接 192.168.17.11:11111

生产中不建议使用,因为需要打开端口。

arthas

阿里巴巴通过JVMTI写成的在线排查工具。

在生产上我们经常会碰到一些不好排查的问题,例如线程安全问题,用最简单的threaddump或者heapdump不好查到问题原因。为了排查这些问题,有时我们会临时加一些日志,比如在一些关键的函数里打印出入参,然后重新打包发布,如果打了日志还是没找到问题,继续加日志,重新打包发布。对于上线流程复杂而且审核比较严的公司,从改代码到上线需要层层的流转,会大大影响问题排查的进度。

java -jar arthas-boot.jar启动,并选择要挂载的进程。

常用命令:

  • dashboard:观察系统情况

  • jvm:比jinfo更强大,显示信息
  • thread 51:定位51号线程问题,查看线程占cpu情况 thread -b 显示死锁
  • sc *top.tjtulong*:搜索加载的类
  • sm *top.tjtulong.ArthasLearn*:搜索方法
  • trace:追踪某个方法的执行时间
  • heapdump:导出堆存储快照
  • jad:反编译类

日志分析

CMS日志

执行命令:java -Xms20M -Xmx20M -XX:+PrintGCDetails -XX:+UseConcMarkSweepGC com.mashibing.jvm.gc.T15_FullGC_Problem01

YGC

[GC (Allocation Failure) [ParNew: 6144K->640K(6144K), 0.0265885 secs] 6585K->2770K(19840K), 0.0268035 secs] [Times: user=0.02 sys=0.00, real=0.02 secs] 
//ParNew:年轻代收集器
//6144->640:收集前后的对比
//(6144):整个年轻代容量
//6585 -> 2770:整个堆的情况
//(19840):整个堆大小

CMS-GC

[GC (CMS Initial Mark) [1 CMS-initial-mark: 8511K(13696K)] 9866K(19840K), 0.0040321 secs] [Times: user=0.01 sys=0.00, real=0.00 secs] 
	//8511 (13696) : 老年代使用(最大)
	//9866 (19840) : 整个堆使用(最大)
[CMS-concurrent-mark-start]
[CMS-concurrent-mark: 0.018/0.018 secs] [Times: user=0.01 sys=0.00, real=0.02 secs] 
	//并发标记这里的时间意义不大,因为是并发执行
[CMS-concurrent-preclean-start]
[CMS-concurrent-preclean: 0.000/0.000 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
	//预清理,标记Card为Dirty,也称为Card Marking
[GC (CMS Final Remark) [YG occupancy: 1597 K (6144 K)][Rescan (parallel) , 0.0008396 secs][weak refs processing, 0.0000138 secs][class unloading, 0.0005404 secs][scrub symbol table, 0.0006169 secs][scrub string table, 0.0004903 secs][1 CMS-remark: 8511K(13696K)] 10108K(19840K), 0.0039567 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
	//最终标记STW阶段,YG occupancy:年轻代占用及容量
	//[Rescan (parallel):STW下的存活对象标记
	//weak refs processing: 弱引用处理
	//class unloading: 卸载用不到的class
	//scrub symbol(string) table: 
		//cleaning up symbol and string tables which hold class-level metadata and 
		//internalized string respectively
	//CMS-remark: 8511K(13696K): 阶段过后的老年代占用及容量
	//10108K(19840K): 阶段过后的堆占用及容量

[CMS-concurrent-sweep-start]
[CMS-concurrent-sweep: 0.005/0.005 secs] [Times: user=0.00 sys=0.00, real=0.01 secs] 
	//标记已经完成,进行并发清理
[CMS-concurrent-reset-start]
[CMS-concurrent-reset: 0.000/0.000 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
	//重置内部结构,为下次GC做准备

G1日志详解

[GC pause (G1 Evacuation Pause) (young) (initial-mark), 0.0015790 secs]
//young -> 年轻代 Evacuation-> 复制存活对象 
//initial-mark 混合回收的阶段,这里是YGC混合老年代回收
   [Parallel Time: 1.5 ms, GC Workers: 1] //一个GC线程
      [GC Worker Start (ms):  92635.7]
      [Ext Root Scanning (ms):  1.1]
      [Update RS (ms):  0.0]
         [Processed Buffers:  1]
      [Scan RS (ms):  0.0]
      [Code Root Scanning (ms):  0.0]
      [Object Copy (ms):  0.1]
      [Termination (ms):  0.0]
         [Termination Attempts:  1]
      [GC Worker Other (ms):  0.0]
      [GC Worker Total (ms):  1.2]
      [GC Worker End (ms):  92636.9]
   [Code Root Fixup: 0.0 ms]
   [Code Root Purge: 0.0 ms]
   [Clear CT: 0.0 ms]
   [Other: 0.1 ms]
      [Choose CSet: 0.0 ms]
      [Ref Proc: 0.0 ms]
      [Ref Enq: 0.0 ms]
      [Redirty Cards: 0.0 ms]
      [Humongous Register: 0.0 ms]
      [Humongous Reclaim: 0.0 ms]
      [Free CSet: 0.0 ms]
   [Eden: 0.0B(1024.0K)->0.0B(1024.0K) Survivors: 0.0B->0.0B Heap: 18.8M(20.0M)->18.8M(20.0M)]
 [Times: user=0.00 sys=0.00, real=0.00 secs] 
//以下是混合回收其他阶段
[GC concurrent-root-region-scan-start]
[GC concurrent-root-region-scan-end, 0.0000078 secs]
[GC concurrent-mark-start]
//无法evacuation,进行FGC
[Full GC (Allocation Failure)  18M->18M(20M), 0.0719656 secs]
   [Eden: 0.0B(1024.0K)->0.0B(1024.0K) Survivors: 0.0B->0.0B Heap: 18.8M(20.0M)->18.8M(20.0M)], [Metaspace: 38
76K->3876K(1056768K)] [Times: user=0.07 sys=0.00, real=0.07 secs]

常用参数配置

GC常用参数

  • -Xmn -Xms -Xmx -Xss
    年轻代 最小堆 最大堆 栈空间

  • -XX:+UseTLAB
    使用TLAB(线程独占缓冲区),默认打开

  • -XX:+PrintTLAB
    打印TLAB的使用情况

  • -XX:TLABSize
    设置TLAB大小

  • -XX:+DisableExplictGC
    System.gc()不管用 ,FGC

  • -XX:+PrintGC

  • -XX:+PrintGCDetails

  • -XX:+PrintHeapAtGC

  • -XX:+PrintGCTimeStamps

  • -XX:+PrintGCApplicationConcurrentTime (重要性低)
    打印应用程序时间

  • -XX:+PrintGCApplicationStoppedTime (重要性低)
    打印暂停时长

  • -XX:+PrintReferenceGC (重要性低)
    记录回收了多少种不同引用类型的引用

  • -verbose:class
    类加载详细过程

  • -XX:+PrintVMOptions

    在运行时,打印虚拟机接收到命令行显示参数

  • -XX:+PrintFlagsFinal -XX:+PrintFlagsInitial
    查看初始默认值和修改后的参数

  • -Xloggc:opt/log/gc.log

    输出GC日志的位置

  • -XX:MaxTenuringThreshold
    升代年龄,最大值15

  • 锁自旋次数 -XX:PreBlockSpin 热点代码检测参数-XX:CompileThreshold 逃逸分析 标量替换 …
    这些不建议设置

Parallel常用参数

  • -XX:SurvivorRatio

    survivor区比例

  • -XX:PreTenureSizeThreshold

    大对象到底多大

  • -XX:MaxTenuringThreshold

  • -XX:+ParallelGCThreads
    并行收集器的线程数,同样适用于CMS,一般设为和CPU核数相同

  • -XX:+UseAdaptiveSizePolicy
    自动选择各区大小比例

  • -XX:MaxGCPauseMillis

    垃圾收集器最大停顿的时间,但最大停顿时间过短必然会导致新生代的内存大小变小,垃圾回收频率变高,效率可能降低

  • -XX:GCTIMERatio

    吞吐量大小(0-100),默认为99

CMS常用参数

  • -XX:+UseConcMarkSweepGC

  • -XX:ParallelCMSThreads
    CMS线程数量

  • -XX:CMSInitiatingOccupancyFraction
    使用多少比例的老年代后开始CMS收集,默认是68%(近似值),如果频繁发生SerialOld卡顿,应该调小,(频繁CMS回收)

  • -XX:+UseCMSCompactAtFullCollection
    在FGC时进行压缩

  • -XX:CMSFullGCsBeforeCompaction
    多少次FGC之后进行压缩(默认是0,即每次都压缩)

  • -XX:+CMSClassUnloadingEnabled

  • -XX:CMSInitiatingPermOccupancyFraction
    达到什么比例时进行Perm回收

  • -XX:CMSPrecleaningEnabled

    开启预清理(默认开启)

  • -XX:GCTimeRatio
    设置GC时间占用程序运行时间的百分比

  • -XX:MaxGCPauseMillis
    停顿时间,是一个建议时间,GC会尝试用各种手段达到这个时间,比如减小年轻代

更多参数参考:https://blog.csdn.net/zqz_zqz/article/details/70568819

G1常用参数

  • -XX:+UseG1Gc

  • -XX:G1HeapRegionSize=n

    设置的G1区域的大小,值是2的幂,范围是1-32MB,目标是根据最小的java堆大小划分出约2048个区域;

    随着size增加,垃圾的存活时间更长,GC间隔更长,但每次GC的时间也会更长。

  • -XX:MaxGCPauseMillis=n

    最大GC停顿时间,这是个软目标,JVM将尽可能(但不保证)停顿小于这个时间(100)

  • -XX:InitiatingHeapOccupancyRercent=n

    堆占用了多少的时候就触发GC,默认45

  • -XX:ConcGcThreads=n

    并发GC使用的线程数

  • -XX:G1ReservePercent=n

    设置作为空闲空间的预留内存百分比,以降低目标空间溢出的风险,默认10%

其它案例汇总

来源:马士兵,有一些已经过时,仅供参考o(╯□╰)o

OOM产生的原因多种多样,有些程序未必产生OOM,不断FGC(CPU飙高,但内存回收特别少) (上面案例)

  1. 硬件升级系统反而卡顿的问题(见上)

  2. 线程池不当运用产生OOM问题(见上)
    不断的往List里加对象(实在太LOW)

  3. smile jira问题
    实际系统不断重启
    解决问题 加内存 + 更换垃圾回收器 G1
    真正问题在哪儿?不知道

  4. tomcat http-header-size过大问题(Hector)

  5. lambda表达式导致方法区溢出问题(MethodArea / Perm Metaspace)
    LambdaGC.java -XX:MaxMetaspaceSize=9M -XX:+PrintGCDetails

    "C:\Program Files\Java\jdk1.8.0_181\bin\java.exe" -XX:MaxMetaspaceSize=9M -XX:+PrintGCDetails "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA Community Edition 2019.1\lib\idea_rt.jar=49316:C:\Program Files\JetBrains\IntelliJ IDEA Community Edition 2019.1\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files\Java\jdk1.8.0_181\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\cldrdata.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\jfxrt.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\nashorn.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\sunpkcs11.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\zipfs.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\jfxswt.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\resources.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\rt.jar;C:\work\ijprojects\JVM\out\production\JVM;C:\work\ijprojects\ObjectSize\out\artifacts\ObjectSize_jar\ObjectSize.jar" com.mashibing.jvm.gc.LambdaGC
    [GC (Metadata GC Threshold) [PSYoungGen: 11341K->1880K(38400K)] 11341K->1888K(125952K), 0.0022190 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
    [Full GC (Metadata GC Threshold) [PSYoungGen: 1880K->0K(38400K)] [ParOldGen: 8K->1777K(35328K)] 1888K->1777K(73728K), [Metaspace: 8164K->8164K(1056768K)], 0.0100681 secs] [Times: user=0.02 sys=0.00, real=0.01 secs] 
    [GC (Last ditch collection) [PSYoungGen: 0K->0K(38400K)] 1777K->1777K(73728K), 0.0005698 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
    [Full GC (Last ditch collection) [PSYoungGen: 0K->0K(38400K)] [ParOldGen: 1777K->1629K(67584K)] 1777K->1629K(105984K), [Metaspace: 8164K->8156K(1056768K)], 0.0124299 secs] [Times: user=0.06 sys=0.00, real=0.01 secs] 
    java.lang.reflect.InvocationTargetException
    	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    	at java.lang.reflect.Method.invoke(Method.java:498)
    	at sun.instrument.InstrumentationImpl.loadClassAndStartAgent(InstrumentationImpl.java:388)
    	at sun.instrument.InstrumentationImpl.loadClassAndCallAgentmain(InstrumentationImpl.java:411)
    Caused by: java.lang.OutOfMemoryError: Compressed class space
    	at sun.misc.Unsafe.defineClass(Native Method)
    	at sun.reflect.ClassDefiner.defineClass(ClassDefiner.java:63)
    	at sun.reflect.MethodAccessorGenerator$1.run(MethodAccessorGenerator.java:399)
    	at sun.reflect.MethodAccessorGenerator$1.run(MethodAccessorGenerator.java:394)
    	at java.security.AccessController.doPrivileged(Native Method)
    	at sun.reflect.MethodAccessorGenerator.generate(MethodAccessorGenerator.java:393)
    	at sun.reflect.MethodAccessorGenerator.generateSerializationConstructor(MethodAccessorGenerator.java:112)
    	at sun.reflect.ReflectionFactory.generateConstructor(ReflectionFactory.java:398)
    	at sun.reflect.ReflectionFactory.newConstructorForSerialization(ReflectionFactory.java:360)
    	at java.io.ObjectStreamClass.getSerializableConstructor(ObjectStreamClass.java:1574)
    	at java.io.ObjectStreamClass.access$1500(ObjectStreamClass.java:79)
    	at java.io.ObjectStreamClass$3.run(ObjectStreamClass.java:519)
    	at java.io.ObjectStreamClass$3.run(ObjectStreamClass.java:494)
    	at java.security.AccessController.doPrivileged(Native Method)
    	at java.io.ObjectStreamClass.<init>(ObjectStreamClass.java:494)
    	at java.io.ObjectStreamClass.lookup(ObjectStreamClass.java:391)
    	at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1134)
    	at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1548)
    	at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1509)
    	at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1432)
    	at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1178)
    	at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:348)
    	at javax.management.remote.rmi.RMIConnectorServer.encodeJRMPStub(RMIConnectorServer.java:727)
    	at javax.management.remote.rmi.RMIConnectorServer.encodeStub(RMIConnectorServer.java:719)
    	at javax.management.remote.rmi.RMIConnectorServer.encodeStubInAddress(RMIConnectorServer.java:690)
    	at javax.management.remote.rmi.RMIConnectorServer.start(RMIConnectorServer.java:439)
    	at sun.management.jmxremote.ConnectorBootstrap.startLocalConnectorServer(ConnectorBootstrap.java:550)
    	at sun.management.Agent.startLocalManagementAgent(Agent.java:137)
    
    
  6. 直接内存溢出问题(少见)
    《深入理解Java虚拟机》P59,使用Unsafe分配直接内存,或者使用NIO的问题

  7. 栈溢出问题
    -Xss设定太小

  8. 比较一下这两段程序的异同,分析哪一个是更优的写法:

    Object o = null;
    for(int i=0; i<100; i++) {
        o = new Object();
        //业务处理
    }
    
    for(int i=0; i<100; i++) {
        Object o = new Object();
    }
    
  9. 重写finalize引发频繁GC
    小米云,HBase同步系统,系统通过nginx访问超时报警,最后排查,C++程序员重写finalize引发频繁GC问题
    为什么C++程序员会重写finalize?(new delete)
    finalize耗时比较长(200ms)

  10. 如果有一个系统,内存一直消耗不超过10%,但是观察GC日志,发现FGC总是频繁产生,会是什么引起的?
    System.gc() (这个比较Low)

  11. Distuptor有个可以设置链的长度,如果过大,然后对象大,消费完不主动释放,会溢出 (来自 死物风情)

  12. 用jvm都会溢出,mycat用崩过,1.6.5某个临时版本解析sql子查询算法有问题,9个exists的联合sql就导致生成几百万的对象(来自 死物风情)

  13. new 大量线程,会产生 native thread OOM,(low)应该用线程池,
    解决方案:减少堆空间(太TMlow了),预留更多内存产生native thread
    JVM内存占物理内存比例 50% - 80%

  14. CMS调优案例:https://www.cnblogs.com/gxyandwmm/p/9456955.html

-Xms128m  
-Xmx128m  
-Xmn36m  
-XX:PermSize=80m  
-XX:MaxPermSize=80m  
-Xss:256k  
-XX:SurvivorRatio=1 
-XX:MaxTenuringThreshold=20 
-XX:+UseParNewGC  
-XX:+UseConcMarkSweepGC  
-XX:CMSInitiatingOccupancyFraction=73 
-XX:+UseCMSCompactAtFullCollection  
-XX:+CMSParallelRemarkEnabled  
-XX:CMSFullGCsBeforeCompaction=2 
-XX:SoftRefLRUPolicyMSPerMB=0 
-XX:+PrintClassHistogram  
-XX:+PrintGCDetails  
-XX:+PrintGCTimeStamps  
-XX:+PrintHeapAtGC  
-Xloggc:logs/gc.log  
-Dsun.rmi.dgc.server.gcInterval=3600000 
-Dsun.rmi.dgc.client.gcInterval=3600000 
-Dsun.rmi.server.exceptionTrace=true
  • 3
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
当涉及到Nginx和JVM的调优时,我们可以从两个方面来讨论。 首先是Nginx的调优。Nginx是一个高性能的Web服务器和反向代理服务器,以下是一些常见的Nginx调优方法: 1. 调整worker_processes和worker_connections:根据服务器的硬件配置和负载情况,适当调整worker_processes(工作进程数)和worker_connections(每个工作进程的最大连接数)参数,以提高并发处理能力。 2. 启用gzip压缩:开启gzip压缩可以减小传输的数据量,提高网站的响应速度。 3. 调整缓冲区大小:通过调整proxy_buffer_size、proxy_buffers和proxy_busy_buffers_size等参数,可以优化Nginx对后端服务器的请求和响应的缓冲区管理,提高性能。 4. 使用缓存:使用Nginx的缓存功能可以减轻后端服务器的负载,提高响应速度。可以通过配置proxy_cache和相关参数来启用缓存。 5. 负载均衡:通过配置upstream模块,可以实现Nginx的负载均衡功能,将请求分发到多个后端服务器上,提高系统的可用性和性能。 接下来是JVM的调优。JVM是Java虚拟机的缩写,以下是一些常见的JVM调优方法: 1. 调整堆内存大小:通过调整-Xms和-Xmx参数,可以设置JVM的初始堆大小和最大堆大小,以适应应用程序的内存需求。 2. 设置垃圾回收器:根据应用程序的特点和性能需求,选择合适的垃圾回收器,如Serial GC、Parallel GC、CMS GC或G1 GC,并通过相关参数进行配置。 3. 调整线程数:通过调整-Xss参数,可以设置线程栈的大小,以及通过调整-XX:ParallelGCThreads参数来设置并行垃圾回收线程数,以提高并发处理能力。 4. 监控和分析工具:使用JVM提供的监控和分析工具,如jstat、jconsole、jvisualvm等,可以实时监控JVM的运行状态和性能指标,帮助定位性能瓶颈和优化机会。 5. 代码优化:通过对代码进行优化,如减少对象的创建、避免过多的同步、合理使用缓存等,可以减少JVM的负载,提高性能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值