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 Control的JOverflow插件中并对其进行分析各种内存问题。

注意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. printf 函数笔记

    函数声明 int printf (const char*, ...); 说明 <返回值> printf ("<格式化字符串>", <参数表>); ...

  2. Git提交代码和更新代码命令

    微信公众号:非科班的科班关注可了解更多的java教程和其它资源视频.问题或建议,请公众号留言; 1.Git提交代码 利用命令提交代码的步骤:1.1.拉取服务器代码,避免覆盖他人的代码 git pull ...

  3. Spring注解开发系列专栏

    这个系列主要是讲Spring注解的使用,可以为后面SpringBoot的学习带来一定的帮助.我觉得从Spring直接过度到SpringBoot还是有点快,还是得需要一个演变的过程.从Spring开发, ...

  4. CUDA学习(五)之使用共享内存(shared memory)进行归约求和(一个包含N个线程的线程块)

    共享内存(shared memory)是位于SM上的on-chip(片上)一块内存,每个SM都有,就是内存比较小,早期的GPU只有16K(16384),现在生产的GPU一般都是48K(49152). ...

  5. 惠普电脑win10关闭自动调节亮度

    自动调节亮度真的太烦人了,突然从亮的画面变暗,又从暗的亮度变量,眼睛受不了.但是试了很多种方法都不行. 方法 第一种: 有一些电脑是有在设置--->显示界面--->有一个 关闭自动调节 按 ...

  6. C语言之灵魂 指针学习

    指针是c语言的难点 称之为c语言的灵魂一点也不为过,不过指针用好了能事半功倍,用不好bug满天飞. 一.指针的概念 指针也是变量只不过是特殊的变量,指针的值是另一个变量的地(也就是变量所在的内存地址) ...

  7. POJ_3663_贪心

    题目描述: 给你一堆数和一个限定的空间大小,要求求出两个数的和小于等于空间大小的对数. 思路: 贪心,先给一堆数从大到小排序. 第一个数取数组第一个,第二个数从第二个开始依次往后取,只要某个第二个数满 ...

  8. HDU_3415_单调队列

    http://acm.hdu.edu.cn/showproblem.php?pid=3415 初探单调队列,需要注意的是每次i维护的是i-1. #include<iostream> #in ...

  9. Intel发布神经网络压缩库Distiller:快速利用前沿算法压缩PyTorch模型——AttributeError: module ‘tensorboard' has no attribute 'lazy'

    转载自:CSDN Nine-days   近日,Intel 开源了一个用于神经网络压缩的开源 Python 软件包 Distiller,它可以减少深度神经网络的内存占用.加快推断速度及节省能耗.Dis ...

  10. Codeforces 1188B Count Pairs (同余+分离变量)

    题意: 给一个3e5的数组,求(i,j)对数,使得$(a_i+a_j)(a_i^2+a_j^2)\equiv k\ mod\ p$ 思路: 化简$(a_i^4-a_j^4)\equiv k(a_i-a ...