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. 使用postman测试接口

    1.什么是接口测试 其实接口测试就和普通功能测试没什么区别,区别就是功能测试是在页面上点点点,在页面上输入值,提交数据看结果,而接口测试没有页面,通过接口规范文档上的调用地址.请求参数,拼接报文,然后 ...

  2. Web前端-HTML、CSS、JS

    概述 HTML是英文Hyper Text Mark-up Language(超文本标记语言)的缩写,它是一种制作万维网页面标准语言(标记).相当于定义统一的一套规则,大家都来遵守他, 这样就可以让浏览 ...

  3. H5新增特性

    1.pattern:写正则,但是需要和form表单连着用 2.WebSocket "网络套接字", 是 HTML5 开始提供的一种在单个 TCP 连接上进行全双工通讯的协议.在 W ...

  4. Docker基础内容之仓库

    前言 Docker提供了开放的中央仓库dockerhub,同时也允许我们使用registry搭建本地私有仓库.搭建私有仓库有如下的优点: 节省网络带宽,提升Docker部署速度,不用每个镜像从Dock ...

  5. 浅谈synchronized

    目录 浅谈synchronized 前言 是什么 格式 同步代码块 同步方法 注意 最后 浅谈synchronized 前言 看多线程的相关书籍的时候,会经常阅读到一个使用前景,就是银行的取钱存钱操作 ...

  6. springboot中使用自定义注解实现策略模式,去除工厂模式的switch或ifelse,实现新增策略代码零修改

    前言 思路与模拟业务 源码地址 https://gitee.com/houzheng1216/springboot 整体思路就是通过注解在策略类上指定约定好的type,项目启动之后将所有有注解的typ ...

  7. Oracle批量创建同义词

    一.介绍 Oracle的同义词(synonyms)从字面上理解就是别名的意思,和视图的功能类似,就是一种映射关系.它可以节省大量的数据库空间,对不同用户的操作同一张表没有多少差别;它扩展了数据库的使用 ...

  8. A Simple Introduction To Computer Networking

    Most networking discussions are a jumble of acronyms. Forget the configuration details - what are th ...

  9. TypeError:Can't instantiate abstract class Ultraman with abstract methods sttack 报错

    报错Can't instantiate abstract class Ultraman with abstract methods sttack 通过非常仔细的排查,发现错误如下: 1.单词拼写错误是 ...

  10. caffe 指定GPU

    caffe默认使用编号为0的gpu, 若它的内存不够或正忙, 即使有其余gpu空闲, caffe也不会使用. 要用哪个gpu, 就要明确指定哪个. 不指定则使用默认. 命令行 ./build/tool ...