Arthas是一个Java诊断工具,用于在线诊断Java应用程序,以便更轻松地监控和分析应用程序的性能和行为。Arthas中有许多用于诊断Java应用程序的命令。
1. jvm
和 dashboard
命令的区别:
-
jvm
:该命令用于显示当前的JVM信息,包括类加载信息、内存使用情况、GC信息等。它提供了一个快照视图,详细地显示了JVM的内部状态。这有助于识别资源限制或配置问题。 -
dashboard
:该命令用于显示应用程序的实时数据仪表板,包括JVM信息、线程状态和吞吐量等。它显示的信息比jvm
命令更加概要和可视化,主要关注应用程序的整体性能和运行状况。
总结:jvm
命令关注详细的JVM信息,而dashboard
命令则提供了应用程序的整体性能概览。
2. sysprop
和 sysenv
的区别:
-
sysprop
:该命令用于显示或修改Java系统属性。系统属性是JVM启动时由命令行参数、配置文件或代码设置的键值对。它们可以在运行时使用System.getProperty
方法检索,并常常用于配置应用程序行为。 -
sysenv
:该命令用于显示操作系统的环境变量。环境变量是操作系统提供的键值对,通常由操作系统或shell启动脚本设置。它们可以在运行时使用System.getenv
方法检索,并常常用于配置应用程序环境。
总结:sysprop
命令关注Java系统属性,而sysenv
命令关注操作系统的环境变量。
3 那arthas的vmoption是干什么的
vmoption
命令在 Arthas 中用于查看和修改 JVM 启动选项。JVM 启动选项是在 JVM 启动时设置的一系列参数,它们可以用于配置 JVM 的行为,例如堆大小、垃圾收集器类型、启用或禁用某些特性等。
使用 vmoption
命令,你可以在不重启 JVM 的情况下动态地查看或修改某些 JVM 启动选项。请注意,不是所有的 JVM 启动选项都支持动态修改,某些选项只能在 JVM 启动时设置。
使用 vmoption
命令查看当前的 JVM 启动选项:
shell
vmoption
使用 vmoption
命令修改 JVM 启动选项(例如,启用类数据共享):
shell
vmoption -set UseSharedSpaces=true
请注意,在使用 vmoption
命令修改 JVM 启动选项时,应该小心谨慎,因为某些选项的修改可能会对 JVM 的行为产生重大影响。在修改之前,建议先仔细阅读相关的 JVM 文档和选项描述。
4 vmoption和sysprop的区别
vmoption
和 sysprop
是 Arthas 中的两个不同的命令,它们分别用于查看或修改 JVM 启动选项和 Java 系统属性。虽然它们都涉及到 Java 运行时的配置,但它们的用途和作用范围不同。
-
vmoption
:- 用途:查看或修改 JVM 启动选项。
- 作用范围:影响整个 JVM 的行为和配置。
- 设置时机:通常在 JVM 启动时通过命令行参数设置。一些选项可以在运行时使用
vmoption
命令动态修改。 - 示例:设置堆大小(
-Xms
,-Xmx
)、选择垃圾收集器(-XX:+UseG1GC
)、启用类数据共享(-XX:+UseSharedSpaces
)等。 - 访问方式:不能在 Java 代码中直接访问。
-
sysprop
:- 用途:查看或修改 Java 系统属性。
- 作用范围:影响 Java 应用程序的行为和配置。
- 设置时机:可以在 JVM 启动时通过命令行参数(
-Dkey=value
)设置,也可以在运行时使用System.setProperty
方法设置。 - 示例:设置文件编码(
file.encoding
)、设置 Java 临时目录(java.io.tmpdir
)、设置用户自定义的应用配置等。 - 访问方式:可以在 Java 代码中使用
System.getProperty
方法访问。
总结:vmoption
主要用于配置 JVM 的行为,而 sysprop
主要用于配置 Java 应用程序的行为。它们的设置方式和访问方式也有所不同。
5 sysprop只能针对单个应用程序吗,然后vmoption的参数对这个jvm内的所有java应用都有影响?
是的,你的理解是正确的。
-
sysprop
(系统属性):- 针对单个应用程序:系统属性是在特定的Java应用程序上下文中设置的。每个Java应用程序都有自己的系统属性集,它们只对该应用程序的运行实例有效。设置或修改系统属性不会影响其他运行在同一JVM中的应用程序。
- 访问方式:在Java代码中,可以使用
System.getProperty
方法读取系统属性,或使用System.setProperty
方法设置系统属性。
-
vmoption
(JVM启动选项):- 对JVM中所有应用程序有效:JVM启动选项是在JVM启动时设置的,并且对JVM中所有运行的Java应用程序都有效。设置或修改这些选项会影响整个JVM及其中的所有应用程序。
- 访问方式:通常在启动JVM时通过命令行参数设置,如
java -Xms512m -Xmx1024m MyApp
。一些选项可以在运行时使用Arthas的vmoption
命令动态修改。
总结:sysprop
是针对单个Java应用程序的,而vmoption
对整个JVM及其中的所有应用程序都有效。
6 sysprop只能针对单个应用程序吗,然后vmoption的参数对这个jvm内的所有java应用都有影响?
是的,你的理解是正确的。
-
sysprop
(系统属性):- 针对单个应用程序:系统属性是在特定的Java应用程序上下文中设置的。每个Java应用程序都有自己的系统属性集,它们只对该应用程序的运行实例有效。设置或修改系统属性不会影响其他运行在同一JVM中的应用程序。
- 访问方式:在Java代码中,可以使用
System.getProperty
方法读取系统属性,或使用System.setProperty
方法设置系统属性。
-
vmoption
(JVM启动选项):- 对JVM中所有应用程序有效:JVM启动选项是在JVM启动时设置的,并且对JVM中所有运行的Java应用程序都有效。设置或修改这些选项会影响整个JVM及其中的所有应用程序。
- 访问方式:通常在启动JVM时通过命令行参数设置,如
java -Xms512m -Xmx1024m MyApp
。一些选项可以在运行时使用Arthas的vmoption
命令动态修改。
总结:sysprop
是针对单个Java应用程序的,而vmoption
对整个JVM及其中的所有应用程序都有效。
7 arthas的jad命令是干啥的,为什么这么叫
jad
命令用于将Java类文件反编译成Java源代码。它可以帮助你查看正在运行的Java应用程序的源代码,即使你没有访问原始源代码。"jad"这个名字来自于早期的一个流行Java反编译器工具,该工具也叫做JAD(Java Decompiler)。
8 mc呢?
mc
(Memory Compiler)命令用于内存编译和动态加载Java类。它允许你在不重新启动Java应用程序的情况下,直接在内存中修改和重新加载Java类。这可以方便地修复Bug、调试应用程序或者测试代码更改。
9 arthas和jprofile的区别
-
Arthas:是阿里巴巴开源的一个Java诊断工具,专注于在线诊断Java应用程序。它提供了许多功能,包括查看JVM信息、反编译Java类、动态加载Java类、监控方法调用、追踪方法执行等。Arthas是一个轻量级工具,适合在生产环境中使用,不需要重新启动Java应用程序即可附加和诊断。
-
JProfiler:是一个商业的Java性能剖析器,主要用于性能分析和优化。它提供了许多功能,包括CPU分析、内存分析、线程分析、数据库分析等。JProfiler通常用于开发环境,帮助开发者找出性能瓶颈、内存泄漏和线程问题。JProfiler有图形用户界面(GUI),方便可视化分析性能数据。
总结:
- Arthas更适合在线诊断和排查问题,不需要重新启动应用程序即可使用。
- JProfiler更适合开发和测试环境,主要用于性能分析和优化。
- Arthas是开源工具,JProfiler是商业工具。
10 为什么 redefine命令要设置为修改完成不可恢复?
redefine
命令的行为是基于 Java 语言的 Instrumentation
接口中的 redefineClasses
方法实现的。这个方法是 JVM 提供的一个功能,允许在运行时替换类的字节码。它通常用于热修复、热部署等场景。
当我们使用 redefine
命令时,我们实际上是在运行时替换了类的字节码。这是一个不可逆的操作,因为 JVM 不会保存原始的字节码。一旦我们重新定义了类,JVM 中的类将使用新的字节码,并且无法恢复到原始状态。
这里的不可逆性不是 Arthas 的设计决策,而是基于 JVM 的限制。redefineClasses
方法只能替换字节码,但不提供恢复原始字节码的功能。
如果需要在 redefine
之后恢复到原始的字节码,可以手动保存类的原始字节码,然后在需要恢复时使用 redefine
命令重新加载原始字节码。
需要注意的是,在重新定义类时,有一些限制。例如,不能添加、删除或修改类的字段和方法签名。这是因为这样的更改可能会导致已加载的类和新字节码之间的不兼容性,并且可能会导致运行时错误。
11 为什么 redefine命令要设置为修改完成不可恢复
redefine
命令的行为是基于 Java 语言的 Instrumentation
接口中的 redefineClasses
方法实现的。这个方法是 JVM 提供的一个功能,允许在运行时替换类的字节码。它通常用于热修复、热部署等场景。
当我们使用 redefine
命令时,我们实际上是在运行时替换了类的字节码。这是一个不可逆的操作,因为 JVM 不会保存原始的字节码。一旦我们重新定义了类,JVM 中的类将使用新的字节码,并且无法恢复到原始状态。
这里的不可逆性不是 Arthas 的设计决策,而是基于 JVM 的限制。redefineClasses
方法只能替换字节码,但不提供恢复原始字节码的功能。
如果需要在 redefine
之后恢复到原始的字节码,可以手动保存类的原始字节码,然后在需要恢复时使用 redefine
命令重新加载原始字节码。
需要注意的是,在重新定义类时,有一些限制。例如,不能添加、删除或修改类的字段和方法签名。这是因为这样的更改可能会导致已加载的类和新字节码之间的不兼容性,并且可能会导致运行时错误。
12 redefine为什么会和reset冲突
redefine
和 reset
命令冲突的原因主要在于它们的工作机制和目的不同。
-
redefine
命令:redefine
命令用于加载外部的.class
文件,重新定义到 JVM 里。它是一种热替换技术,允许你在不重新启动应用程序的情况下,直接替换已加载的类的字节码。redefine
命令使用的是 JVM 的Instrumentation
接口中的redefineClasses
方法来实现字节码替换。 -
reset
命令:reset
命令用于重置所有增强的类,恢复到没有任何 Arthas 增强(例如监视、追踪等)的原始状态。reset
命令的目的是移除 Arthas 对类的修改,还原类的字节码到应用程序启动时的状态。
冲突的原因:
当你使用 redefine
命令替换类的字节码后,Arthas 的 reset
命令不能识别这个新的字节码(因为这个新的字节码不是应用程序启动时的字节码)。因此,reset
命令不能正确地恢复 redefine
后的类到其原始状态。
同样,当你执行 redefine
命令后,如果再执行如 jad
、watch
、trace
、monitor
、tt
等命令,则可能会把 redefine
的字节码重置,因为这些命令可能会触发类的重新加载。
为了避免这种冲突,建议在使用 redefine
命令之前先执行 reset
命令,确保所有增强的类都已重置。然后再使用 redefine
命令替换类的字节码。在替换字节码后,如果需要使用其他 Arthas 命令,请谨慎操作,避免意外地重置 redefine
后的字节码。
13 因为这个字节码是被替换的,而不是在原来的基础上修改的是嘛
是的,当使用 redefine
命令时,你实际上是完全替换了目标类的字节码,而不是在原有字节码的基础上进行修改。这就是为什么 reset
命令不能识别重新定义后的字节码的原因。
14 那使用redefine,使用了reset命令,除了被redefine的文件,其他的文件应该都能恢复到应用程序启动时的状态吧,会对应用程序产生影响嘛
是的,reset
命令将其他被 Arthas 增强的类恢复到应用程序启动时的状态。只有使用 redefine
命令替换的类不能被恢复。这不会对应用程序产生影响,只是该特定类的字节码不能被恢复。
15 如果使用了redefine,reset失效,那有什么办法恢复到应用程序启动时的状态呢?
恢复到应用程序启动时的状态的方法:
- 手动恢复 :在使用
redefine
命令之前,手动保存目标类的原始字节码。当需要恢复时,再次使用redefine
命令,将保存的原始字节码重新加载到 JVM 中。 - 重启应用程序:如果无法手动恢复,重启应用程序是最简单且最可靠的方法。重启应用程序会使 JVM 重新加载所有的类,从而恢复到应用程序启动时的状态。
请注意,redefine
命令适用于紧急情况下的热修复或热部署。在开发和测试阶段,推荐使用常规的开发、测试和部署流程。在生产环境中使用 redefine
命令时,请确保充分测试,并做好相应的风险评估和备份。
16 classloader命令
16.1 classloader -t 显示类加载器的层次与继承关系
±BootstrapClassLoader
±sun.misc.Launcher E x t C l a s s L o a d e r @ 6 d 6 f 6 e 28 + − c o m . t a o b a o . a r t h a s . a g e n t . A r t h a s C l a s s l o a d e r @ 464 c d 0 d 8 + − s u n . m i s c . L a u n c h e r ExtClassLoader@6d6f6e28 +-com.taobao.arthas.agent.ArthasClassloader@464cd0d8 +-sun.misc.Launcher ExtClassLoader@6d6f6e28+−com.taobao.arthas.agent.ArthasClassloader@464cd0d8+−sun.misc.LauncherAppClassLoader@18b4aac2
±java.net.FactoryURLClassLoader@170c01c5
Affect(row-cnt:5) cost in 1 ms.
这是 Arthas 中的 classloader
命令的输出,它显示了 JVM 中的类加载器层次结构。
在 JVM 中,类加载器是按照层次结构组织的,每个类加载器(除了引导类加载器)都有一个父加载器。这种组织方式有助于实现类加载器的双亲委派模型。
在这个例子中:
BootstrapClassLoader
是 JVM 的引导类加载器。它负责加载 JVM 的核心类库(例如 java.lang.* 类)。sun.misc.Launcher$ExtClassLoader@6d6f6e28
是扩展类加载器。它负责加载位于<JAVA_HOME>/jre/lib/ext
目录或由系统属性java.ext.dirs
指定的目录中的类。com.taobao.arthas.agent.ArthasClassloader@464cd0d8
是 Arthas 的类加载器。它负责加载 Arthas 自身的类。sun.misc.Launcher$AppClassLoader@18b4aac2
是应用程序类加载器。它负责加载应用程序类,通常位于类路径(classpath)上。java.net.FactoryURLClassLoader@170c01c5
是一个自定义的类加载器。它可能用于加载额外的资源或插件。
每行的前缀 +
或 -
表示该类加载器的层次结构。+
表示它有子类加载器,-
表示它没有子类加载器。
这个输出非常有用,因为它可以帮助你了解类加载器的结构和层次,从而更好地理解类是如何被加载的。这对于诊断类加载相关的问题(例如类版本冲突、类未找到、类转换异常等)非常有用。
16.2 在双亲委派模型中,BootstrapClassLoader 是最顶层的加载器,ExtClassLoader是它的子类吧?为什么这里显示两个同级?
在双亲委派模型中,BootstrapClassLoader
是最顶层的加载器,但它是一个特殊的加载器,不是 Java 中的一个对象。因此,在类加载器的层次结构中,BootstrapClassLoader
通常不会显示为其他类加载器的父加载器。
具体来说,BootstrapClassLoader
是 JVM 的一部分,它是用 C++ 编写的,并且不暴露为 Java 对象。这是为什么你在 Java 程序中无法获取到 BootstrapClassLoader
的实例的原因。
在 Java 中,所有其他的类加载器都是 java.lang.ClassLoader
类的实例。ExtClassLoader
和 AppClassLoader
是 URLClassLoader
的实例,而 URLClassLoader
是 ClassLoader
的子类。在 Java 的类加载器层次结构中,ExtClassLoader
是 AppClassLoader
的父加载器。
在 Arthas 的 classloader
命令的输出中,BootstrapClassLoader
显示在最顶层,并且与 ExtClassLoader
并列显示。这是因为 BootstrapClassLoader
不是 Java 对象,它不会作为其他加载器的父加载器显示。但实际上,BootstrapClassLoader
是最顶层的加载器,ExtClassLoader
是它的子类。