Java性能调优指南–有关提高Java代码性能的各种技巧。

最近又学到了很多新知识,感谢优锐课老师细致地讲解,这篇博客记录下自己所学所想。

1. 介绍

在Java世界中,我们大多数人习惯于在Java应用程序开发的所有阶段使用GUI工具:编写代码,对其进行调试和分析。我们通常更喜欢在开发环境中设置服务器环境,并尝试使用熟悉的工具在本地重现问题。不幸的是,由于各种原因,通常不可能在本地重现一些问题。例如,你可能无权访问服务器应用程序处理的真实客户端数据。

在这种情况下,你需要在服务器盒上远程对应用程序进行故障排除。你应该记住,你无法使用裸露的JRE来正确地对应用程序进行故障排除:它包含所有故障排除功能,但是实际上无法访问它。结果,你需要在同一盒子上使用JDK或某些第三方工具。本文将介绍JDK工具,因为与许多组织中需要安全审核的任何第三方工具相比,你可能被允许在生产环境中使用它。

通常,仅需将JDK发行包解压缩到你的包装盒中就足够了——你不需要出于故障排除的目的而正确安装它(实际上,在很多情况下不希望正确安装)。 对于基于JMX的功能,你实际上可以安装任何Java 7/8 JDK,但是某些工具无法识别将来的JDK,因此我建议你安装最新的Java 7/8 JDK或与服务器JRE完全匹配的内部版本-它允许 你会为当前没有访问安全点的应用程序转储应用程序堆(某些处于空闲模式的应用程序是“无安全点”应用程序的简单示例)。

2. 故障排除方案

2.1. 获取正在运行的JVM的列表

为了开始工作,你几乎总是需要获取正在运行的JVM,它们的进程ID和命令行参数的列表。 有时可能就足够了:你可能会发现同一应用程序的第二个实例同时执行相同的工作(并损坏输出文件/重新打开套接字/执行其他一些愚蠢的操作)。

只需运行jcmd而无需任何参数。 它将向你显示正在运行的JVM的列表:

 3824 org.jetbrains.idea.maven.server.RemoteMavenServer
2196
780 sun.tools.jcmd.JCmd

现在,你可以通过运行jcmd <PID> help命令来查看哪些诊断命令可用于给定的JVM。 这是VisualVM的示例输出:

 >jcmd 3036 help

 3036:
The following commands are available:
JFR.stop
JFR.start
JFR.dump
JFR.check
VM.native_memory
VM.check_commercial_features
VM.unlock_commercial_features
ManagementAgent.stop
ManagementAgent.start_local
ManagementAgent.start
GC.rotate_log
Thread.print
GC.class_stats
GC.class_histogram
GC.heap_dump
GC.run_finalization
GC.run
VM.uptime
VM.flags
VM.system_properties
VM.command_line
VM.version
help

键入jcmd <PID> <COMMAND_NAME>来运行诊断命令或得到一条错误消息,询问命令参数:

 >jcmd 3036 GC.heap_dump

 3036:
java.lang.IllegalArgumentException: The argument 'filename' is mandatory.

你可以使用以下命令获取有关诊断命令参数的更多信息:jcmd <PID>帮助<COMMANDNAME>。 例如,这是GC.heap_dump命令的输出:

 >jcmd 3036 help GC.heap_dump

 3036:
GC.heap_dump
Generate a HPROF format dump of the Java heap. Impact: High: Depends on Java heap size and content. Request a full GC unless the '-all' option is specified. Permission: java.lang.management.ManagementPermission(monitor) Syntax : GC.heap_dump [options] <filename> Arguments:
filename : Name of the dump file (STRING, no default value) Options: (options must be specified using the <key> or <key>=<value> syntax)
-all : [optional] Dump all objects, including unreachable objects (BOOLEAN, false)

2.2. 进行堆转储

jcmd为你提供了一个方便的界面,用于以HPROF格式进行堆转储。只需运行jcmd <PID> GC.heap_dump <FILENAME>。请注意,文件名是相对于正在运行的JVM当前目录而不是当前目录的,因此你可能需要指定完整路径。最好使用.hprof扩展名作为转储文件名。

线程转储完成后,你可以将文件复制到自己的盒子中,然后在VisualVM(它是JDK的一部分)中打开它,并使用其堆walker和查询语言功能,或将其加载到Java Mission ControlJOverflow插件中并对其进行分析各种内存问题。

注意1:当然,还有许多其他工具可以处理hprof文件:NetBeans,Eclipse Memory Analyzer,YourKit等。将.hprof文件下载到框中后,请使用你喜欢的工具。

注意2:你也可以使用jmap工具进行堆转储:jmap -dump:live,file = <FILE_NAME> <PID>。问题在于它被正式证明为不受支持。我们中的许多人都认为JDK中不受支持的内容将永远存在,但事实证明情况不再如此:JEP 240,JEP 241

2.3. 分析类直方图

如果你正在寻找内存泄漏,通常只对堆中某些特定类型的活动对象感兴趣。 例如,你可能知道一次只能拥有一个特定类型的对象(应用程序中的某种主要工作类)。 在旧的一代中可能还存在一个或多个相同类的实例,到目前为止,这些实例尚未进行垃圾回收,但是不应从应用程序根目录访问它们。

要打印类直方图,请运行以下两个命令之一(两个命令均打印活动对象的数量):

 jcmd <PID> GC.class_histogram
jmap -histo:live <PID>

以下是示例输出的前几行:

  num     #instances         #bytes  class name
----------------------------------------------
1: 5923 5976952 [I
2: 50034 4127704 [C
3: 49465 1187160 java.lang.String
4: 188 1069496 [J
5: 3985 1067240 [Ljava.util.HashMap$Node;
6: 8756 982872 java.lang.Class
7: 2855 835792 [B
8: 23570 754240 java.util.HashMap$Node
9: 13964 671440 [Ljava.lang.Object;
10: 9642 308544 java.util.Hashtable$Entry
11: 4453 213744 java.util.HashMap

请注意,以字节为单位的已占用大小是一个较浅的大小–它不包含任何子对象。 很容易从char [](类名= [C]和String stats)中注意到这一事实–尽管实例数是相似的(尽管char []-s总是比String多,但是char []-的大小 s明显更大,如果String的大小包含基础char []的大小,则情况并非如此。

现在,你可以grep /搜索你感兴趣的类名称,并检查活动实例的数量。 如果看到的实例超出预期,请进行堆转储并在任何堆遍历器中对其进行分析(请参见上文)。

2.4. 进行线程转储

有时,你的应用程序可能会报告为“not doing anything/got stuck”。有很多种“stuck”的情况——死锁,高资源争用或仅是O(N10)算法来处理数百万用户的请求,在所有这些情况下,你应该知道你的应用程序线程正在执行什么以及锁将执行什么操作他们持有。

有两种类型的锁:基于同步关键字和Object.wait / notifyAll方法的原始锁,以及Java 5中引入的java.util.concurrent锁。它们之间的主要区别是前者绑定到你输入的堆栈框架上同步部分,并且在线程转储中始终可用。另一方面,后者(java.util.concurrent)不受堆栈框架限制——你可以使用一种方法输入锁,然后将其保留在另一种方法中。结果,一段时间以来,它们根本没有在线程转储中打印,即使现在它们仍然是一个选项。但是,你需要在线程转储中同时使用两种锁,以正确调查线程问题。

有3种打印应用程序线程转储的方法。你可以在Linux上运行kill -3 <PID>。 或者,你可以在任何平台上运行以下命令之一:

 jstack <PID>
jcmd <PID> Thread.print

2.5. 运行Java Flight Recorder

到目前为止,本文中提到的所有工具仅应用于快速调查。 为了进行更深入的分析,我建议使用内置的Java Flight Recorder。

运行JFR是一个三步过程:

  1. 你需要创建一个包含所需设置的JFR模板文件。为此,请运行jmc并转到“窗口”->“飞行记录模板管理器”菜单。配置文件准备就绪后,将其导出到文件中,然后将其发送到你正在使用的框中。
  2. JFR需要JDK商业许可证。现在,你需要在所需的JVM上解锁商业功能:
 jcmd <PID> VM.unlock_commercial_features
  1. 之后,你可以启动JFR。 这是命令行示例:
 jcmd <PID> JFR.start name=test duration=60s settings=template.jfc filename=output.jfr

此命令立即运行JFR(未设置delay属性),并使用template.jfc模板文件中的设置并将结果写入output.jfr(在两个文件中都使用绝对路径),收集JVM信息60秒钟。

录制完成后,你可以将.jfr文件复制到笔记本电脑并在jmcGUI中对其进行分析。 它包含几乎所有你需要对JVM进行故障排除的信息,除了完整堆转储,你可以单独创建并复制到你的机器中。

感谢阅读!最后奉上近期整理出来的一套完整的java架构思维导图,分享给大家对照知识点参考学习。

使用JDK工具进行Java服务器应用程序故障排除的更多相关文章

  1. [置顶] JDK工具(一)–Java编译器javac

    1.概述    javac.exe: Java编译器,将Java源代码转换成字节码. 2.用法    javac <选项> <源文件> (使用过程中发现,javac <源 ...

  2. JDK工具(一)–Java编译器javac

    1.概述    javac.exe: Java编译器,将Java源代码转换成字节码. 2.用法    javac <选项> <源文件> (使用过程中发现,javac <源 ...

  3. 三、jdk工具之jstack(Java Stack Trace)

    目录 一.jdk工具之jps(JVM Process Status Tools)命令使用 二.jdk命令之javah命令(C Header and Stub File Generator) 三.jdk ...

  4. 通过JDK常用工具监控Java进程的内存占用情况

    目录 1 JDK 工具的使用 2 查看 GC 日志信息 3 添加 JMS 远程监控 Tomcat是一款常用的Web容器, 它是运行在 JVM(Java Virtual Machine) 中的一个Jav ...

  5. 八、jdk工具之JvisualVM、JvisualVM之二--Java程序性能分析工具Java VisualVM

    目录 一.jdk工具之jps(JVM Process Status Tools)命令使用 二.jdk命令之javah命令(C Header and Stub File Generator) 三.jdk ...

  6. 十、jdk工具之Jdb命令(The Java Debugger)

    目录 一.jdk工具之jps(JVM Process Status Tools)命令使用 二.jdk命令之javah命令(C Header and Stub File Generator) 三.jdk ...

  7. Windows 7下配置JDK环境变量,JAVA环境变量配置,Tomcat服务器的使用

    参考来源: http://www.cnblogs.com/pannysp/archive/2012/03/07/2383364.html 1. 常识: 1.1 War包 War包一般是在进行Web开发 ...

  8. 使用linux perf工具生成java程序火焰图

    pre.cjk { font-family: "Nimbus Mono L", monospace } p { margin-bottom: 0.1in; line-height: ...

  9. 五、jdk工具之jmap(java memory map)、 mat之四--结合mat对内存泄露的分析、jhat之二--结合jmap生成的dump结果在浏览器上展示

    目录 一.jdk工具之jps(JVM Process Status Tools)命令使用 二.jdk命令之javah命令(C Header and Stub File Generator) 三.jdk ...

随机推荐

  1. Hyper-V 搭建独臂路由器(单网卡也可以)

    2020年原本难得清闲的春节,由于疫情的原因只能在家里看视频打发时间.打开某奇艺,全是某某公寓的推荐真的是受不了.一群人在那里叽叽喳喳,超前点播更是吃像难看,实在是没意思,所以决定搞一个独臂路由器玩一 ...

  2. MySql配置环境变量

    完成后安装好MySQL,为MySQL配置环境变量. 0)在我的电脑上点击右键选择属性-->高级系统设置-->环境变量1)新建MYSQL_HOME变量,并配置:D:\Develop\mysq ...

  3. 基于Flask框架搭建视频网站的学习日志(二)

    基于Flask框架搭建视频网站的学习日志(二)2020/02/02 一.初始化 所有的Flask程序都必须创建一个程序实例,程序实例是Flask类的对象 from flask import Flask ...

  4. SparkSQL 如何自定义函数

    1. SparkSql如何自定义函数 2. 示例:Average 3. 类型安全的自定义函数 1. SparkSql如何自定义函数? spark中我们定义一个函数,需要继承 UserDefinedAg ...

  5. Shiro身份验证及授权(二)

    一.Shiro 身份验证 身份验证的步骤: 收集用户身份 / 凭证,即如用户名 / 密码: 调用 Subject.login 进行登录,如果失败将得到相应的 AuthenticationExcepti ...

  6. android webview正确显示音标

    package com.example.fonttest; import android.support.v7.app.ActionBarActivity; import android.webkit ...

  7. 【Qt学习笔记】Qt+VS2010的配置

    http://blog.csdn.net/jocyln9026/article/details/8575218 关于Qt Qt是1991年由Trolltech公司开发的一个跨平台的C++图形用户界面应 ...

  8. ARTS Week 13

    Jan 20, 2020 ~ Jan 26, 2020 Algorithm Problem 141 Linked List Cycle (环形链表) 题目链接 题目描述:给定一个链表,判断链表中是否存 ...

  9. java3选择结构一

    1 public class jh_01_为什么需要if选择结构 { 2 /* 3 * 让它有条件性的去执行某些内容. 4 * System.out.println(2); 5 * 把你要控制的内容放 ...

  10. 【WPF学习】第四十四章 图画

    通过上一章的学习,Geometry抽象类表示形状或路径.Drawing抽象类扮演了互补的角色,它表示2D图画(Drawing)——换句话说,它包含了显示矢量图像或位图需要的所有信息. 尽管有几类画图类 ...