Arthas之类操作

1. classLoader

查询当前JVM中存在的classloader

classloader
 name                                       numberOfInstances  loadedCountTotal
BootstrapClassLoader 1 2340
com.taobao.arthas.agent.ArthasClassloader 1 1345
sun.misc.Launcher$AppClassLoader 1 145
sun.misc.Launcher$ExtClassLoader 1 52
sun.reflect.DelegatingClassLoader 17 17
com.system.framework.CoutomerClassLoader 2 2

查询当前JVM中存在的classloader,注意我们自定义实现的 com.system.framework.CoutomerClassLoader

classloader -l
 name                                                loadedCount  hash      parent
BootstrapClassLoader 2340 null null
com.system.framework.CoutomerClassLoader@6a6824be 1 6a6824be sun.misc.Launcher$AppClassLoader@7cd84586
com.system.framework.CoutomerClassLoader@4aa8f0b4 1 4aa8f0b4 sun.misc.Launcher$AppClassLoader@7cd84586
com.taobao.arthas.agent.ArthasClassloader@5cd3ae63 1345 5cd3ae63 sun.misc.Launcher$ExtClassLoader@7e6cbb7a
sun.misc.Launcher$AppClassLoader@7cd84586 145 7cd84586 sun.misc.Launcher$ExtClassLoader@7e6cbb7a
sun.misc.Launcher$ExtClassLoader@7e6cbb7a 52 7e6cbb7a null

查询当前JVM中classloder之间继承关系,注意我们自定义实现的 com.system.framework.CoutomerClassLoader

classloader -t
+-BootstrapClassLoader
+-sun.misc.Launcher$ExtClassLoader@7e6cbb7a
+-com.taobao.arthas.agent.ArthasClassloader@5cd3ae63
+-sun.misc.Launcher$AppClassLoader@7cd84586
+-com.system.framework.CoutomerClassLoader@6a6824be
+-com.system.framework.CoutomerClassLoader@4aa8f0b4

查询指定的classLoader加载了哪些资源

classloader -c 7e6cbb7a
classloader --classLoaderClass sun.misc.Launcher$ExtClassLoade
file:/C:/Program%20Files/Java/jre1.8.0_221/lib/ext/access-bridge-64.jar
file:/C:/Program%20Files/Java/jre1.8.0_221/lib/ext/cldrdata.jar
...

查询具体资源路径

classloader -c 7cd84586 -r com/system/framework/FrameworkApplicationTests.class
file:/D:/projects/javaprj/framework/target/test-classes/com/system/framework/FrameworkApplicationTests.class

查询指定classloader已经加载的类

classloader -c 4aa8f0b4 -a
hash:1252585652, com.system.framework.CoutomerClassLoader@4aa8f0b4
com.system.framework.EncryptClass

2. Class从哪里加载

通过命令sc查找,重点关注 code-source class-loade classLoaderHash

查找当前环境中加载类中包含EncryptClass的类,code-source为空,表示该class是运行时从代码加载,没有具体路径

sc -d *EncryptClass*
 class-info        com.system.framework.EncryptClass
code-source
name com.system.framework.EncryptClass
isInterface false
isAnnotation false
isEnum false
isAnonymousClass false
isArray false
isLocalClass false
isMemberClass false
isPrimitive false
isSynthetic false
simple-name EncryptClass
modifier public
annotation
interfaces
super-class +-java.lang.Object
class-loader +-com.system.framework.CoutomerClassLoader@6a6824be
+-sun.misc.Launcher$AppClassLoader@7cd84586
+-sun.misc.Launcher$ExtClassLoader@7e6cbb7a
classLoaderHash 6a6824be

code-source 显示具体class加载来源,如果是从jar包中加载会显示具体jar路径

sc -d *CoutomerClassLoader*
class-info        com.system.framework.CoutomerClassLoader
code-source /D:/projects/javaprj/framework/target/test-classes/
name com.system.framework.CoutomerClassLoader
isInterface false
isAnnotation false
isEnum false
isAnonymousClass false
isArray false
isLocalClass false
isMemberClass false
isPrimitive false
isSynthetic false
simple-name CoutomerClassLoader
modifier public
annotation
interfaces
super-class +-java.lang.ClassLoader
+-java.lang.Object
class-loader +-sun.misc.Launcher$AppClassLoader@7cd84586
+-sun.misc.Launcher$ExtClassLoader@7e6cbb7a
classLoaderHash 7cd84586

3. 同名不同版本jar生效版本

根据jar存放位置,推算出对应的classloader,比如查找当前环境加载哪个版本的log4j

classloader -classLoaderClass sun.misc.Launcher$AppClassLoader | grep log4j
file:/D:/maven/org/springframework/boot/spring-boot-starter-log4j2/2.0.5.RELEASE/spring-boot-starter-log4j2-2.0.5.RELEASE.jar
file:/D:/maven/org/apache/logging/log4j/log4j-slf4j-impl/2.10.0/log4j-slf4j-impl-2.10.0.jar
file:/D:/maven/org/apache/logging/log4j/log4j-jul/2.10.0/log4j-jul-2.10.0.jar
file:/D:/maven/org/apache/logging/log4j/log4j-api/2.16.0/log4j-api-2.16.0.jar
file:/D:/maven/org/apache/logging/log4j/log4j-core/2.16.0/log4j-core-2.16.0.jar

从上可知道,当前环境使用的是log4j-api-2.10.0.jar

根据jar中包含的类名,使用sc命令查找

sc -d *LogManager
 class-info        org.apache.logging.log4j.LogManager
code-source /D:/maven/org/apache/logging/log4j/log4j-api/2.16.0/log4j-api-2.16.0.jar
name org.apache.logging.log4j.LogManager
isInterface false
isAnnotation false
isEnum false
isAnonymousClass false
isArray false
isLocalClass false
isMemberClass false
isPrimitive false
isSynthetic false
simple-name LogManager
modifier public
annotation
interfaces
super-class +-java.lang.Object
class-loader +-sun.misc.Launcher$AppClassLoader@7cd84586
+-sun.misc.Launcher$ExtClassLoader@7e6cbb7a
classLoaderHash 7cd84586

从 code-source 中可以知道当前加载的文件具体路径

针对日志框架可以通过logger命名查看codeSource来了解jar来源

logger
 name                      root
class org.apache.logging.log4j.core.config.LoggerConfig
classLoader sun.misc.Launcher$AppClassLoader@7cd84586
classLoaderHash 7cd84586
level INFO
config XmlConfiguration[location=D:\projects\javaprj\framework\target\classes\log4j2.xml]
additivity true
codeSource file:/D:/maven/org/apache/logging/log4j/log4j-core/2.16.0/log4j-core-2.16.0.jar
appenders name Console
class org.apache.logging.log4j.core.appender.ConsoleAppender
classLoader sun.misc.Launcher$AppClassLoader@7cd84586
classLoaderHash 7cd84586
target SYSTEM_OUT

4. 反编译得到源码

从上边classloader列表可以知道,当前JVM中实例化了两个自定义的类加载器CoutomerClassLoader。他们分别加载类 com.system.framework.EncryptClass。当前这个class已经加密,在我们源代码环境是没有这个类源文件。我们自定义加载器,加载代码如下

@Override
public Class<?> loadClass(String name) throws ClassNotFoundException {
byte[] classByte = Base64Utils.decodeFromString(ArtahsDemoClassLoader.encrypt);
if ("com.system.framework.EncryptClass".equals(name)) {
return defineClass(name, classByte, 0, classByte.length);
}
return super.loadClass(name);
}

控制台显示源代码

jad -c 3e2e18f2 --source-only com.system.framework.EncryptClass --lineNumber false

控制台不显示,直接输出文件

jad -c 3e2e18f2 --source-only com.system.framework.EncryptClass --lineNumber false > D:\\EncryptClass.java

得到反编译代码如下

/*
* Decompiled with CFR.
*/
package com.system.framework;
public class EncryptClass {
String note;
public EncryptClass() {
}
public EncryptClass(String note) {
this.note = note;
}
public void print() {
System.out.println("源文件初始输出==>" + this.note);
}
public void setNote(String note) {
this.note = note;
}
public String getNote() {
return this.note;
}
}

从代码可知,当前控制台会打印对应的信息为源文件初始输出==>note。主程序代码每5秒输出一次,输出信息如下

...
======第190次输出======
源文件初始输出==>testRefect--1
源文件初始输出==>testRefect--2
======第191次输出======
源文件初始输出==>testRefect--1
源文件初始输出==>testRefect--2
...

5. 内存编译得到字节码

把反编译文件中的 print方法做如下改动

public void print() {
System.out.println("反编译后重新加载==>" + this.note);
}

执行内存编译编译命令,这里需要注意下,当前运行环境一定是jdk环境而不是jre环境

mc -c 3e2e18f2 -d D:\\ D:\\EncryptClass.java
Memory compiler output:
D:\com\system\framework\EncryptClass.class
Affect(row-cnt:1) cost in 738 ms.

出现如上信息,表示编译成功

6. 加载改动后的Class到JVM

得到我们修改后的class,需要重新装载到JVM以替换之前的class字节码

retransform -c 3e2e18f2 D:\\com\\system\\framework\\EncryptClass.class

成功以后,回到控制台。可以看到输出信息已经改变

======第73次输出======
源文件初始输出==>testRefect--1
源文件初始输出==>testRefect--2
======第74次输出======
反编译后重新加载==>testRefect--1
反编译后重新加载==>testRefect--2

从结果来看,最初猜测,指定classloder,只会影响当前classloader加载的类。可是另一个classloader加载类输出也改变了。说明同一个类的字节码在jvm一定只存在一份

查看已经重新加载过的类

retransform -l
Id              ClassName                                          TransformCount  LoaderHash      LoaderClassName
1 com.system.framework.EncryptClass 1 3e2e18f2 null

还原重新加载前的字节信息,一定依次执行如下两条命令。classPattern 支持通配符

retransform --deleteAll
retransform --classPattern com.system.framework.EncryptClass
======第260次输出======
反编译后重新加载==>testRefect--1
反编译后重新加载==>testRefect--2
======第261次输出======
源文件初始输出==>testRefect--1
源文件初始输出==>testRefect--2

7. 总结

欢迎感兴趣的朋友关注我的订阅号“小院不小”,或点击下方二维码关注。我将多年开发中遇到的难点,以及一些有意思的功能,体会都会一一发布到我的订阅号中

Arthas之类操作的更多相关文章

  1. Arthas - Java 线上问题定位处理的终极利器

    前言 在使用 Arthas 之前,当遇到 Java 线上问题时,如 CPU 飙升.负载突高.内存溢出等问题,你需要查命令,查网络,然后 jps.jstack.jmap.jhat.jstat.hprof ...

  2. Arthas之实例操作

    Arthas之实例操作 1. 静态类属性操作 获取public静态属性 ognl -c 7cd84586 '@com.system.framework.ArtahsDemoClassLoader@pu ...

  3. JAVA神操作--使用Arthas线上热更新实战

    热更不规范,同事两行泪 背景 C君是一个javaer,最近在开发用户登出接口的时候,不小心把接口参数拼错了 正确的是: /api/v1/user/logout?referrer=www.javaer. ...

  4. 线上应用调试利器 --Arthas

    在之前的文章中,我介绍了使用 Btrace 工具进行线上代码的debug (https://www.cnblogs.com/yougewe/p/10180483.html),其大致原理就是通过字节码注 ...

  5. Alibaba Java诊断工具Arthas之快速安装和简单使用

    Alibaba Java诊断工具Arthas简单介绍 : 当你遇到以下类似问题而束手无策时,Arthas可以帮助你解决: 1.这个类从哪个 jar 包加载的?为什么会报各种类相关的 Exception ...

  6. arthas使用介绍

    背景: 一次线上问题的综合排查排查,两个相同的系统的某个模块,数据量更少的系统查询更慢. 先说下整体思路: 查看系统整理负载,网络有100左右毫秒的延迟,看起来影响不大 查看正序运行整体情况,一次查询 ...

  7. 阿里巴巴开源性能监控神器Arthas初体验

    如果问性能测试中最难的是哪部分,相信很多人会说“性能调优”.确实是这样,性能调优是一个非常复杂.技术含量很高的工作.涉及到的知识面很广.以我多年从业经验来看,在企业里,大多数的性能调优都是由开发架构师 ...

  8. 使用Arthas 获取Spring ApplicationContext还原问题现场

    ## 背景 最近来了个实习僧小弟,安排他实现对目标网站 连通性检测的小功能,简单讲就是将下边的shell 脚本换成Java 代码来实现 ``` 1#!/bin/bash 2URL="http ...

  9. 线上问题排查利器Arthas

    官方文档 下载arthas-boot.jar,然后用java -jar的方式启动: curl -O https://alibaba.github.io/arthas/arthas-boot.jar j ...

随机推荐

  1. 暑假撸系统3- petty热更新 mybatis自动填充时间字段!

    经过了昨天纠结技术选型,和一大堆xml配置,终于把架子搭好了.因为最近一次做java项目也在好多年以前了(毕竟用了pytohn以后谁也不想再回来java了),java的生态发生了长足的进步,本来想从原 ...

  2. 四探循环依赖 → 当循环依赖遇上 BeanPostProcessor,爱情可能就产生了!

    开心一刻 那天知道她结婚了,我整整一个晚上没睡觉,开了三百公里的车来到她家楼下,缓缓的抽了一支烟...... 天渐渐凉了,响起了鞭炮声,迎亲车队到了,那天披着婚纱的她很美,真的很美! 我跟着迎亲车队开 ...

  3. Spring 类名后缀理解

    Aware 理解 实现Spring的Aware接口. 定义为感知.意识,核心意义在于通过Aware可以把spring底层组件注入到自定义的bean中. 对于bean与容器的关系,bean不应该知道自身 ...

  4. ansible中的hostvars

    首先来看一个例子:假设我想得到主机IP为172.25.250.9的完全限定域名(FQDN),但是我无法登录该主机,那么就可以用本机里面的hostvars魔法变量(后面会分享我对魔法这个词的理解)这个字 ...

  5. [题解]第十一届北航程序设计竞赛预赛——A.模式

    题目描述 输入一个学号,判断是计算机系or软件学院or其他院系. 解题思路 水题,直接判断or除以10000都可以.不废话,直接上代码. 1 #include <iostream> 2 # ...

  6. 2022必须拥有Chrome扩展程序 - 浏览器插件,让你上网效率翻倍

    在Chrome网上应用店中查找扩展程序 2022必须拥有Chrome扩展程序 - 浏览器插件,让你上网效率翻倍 可扩展的Chrome Web浏览器比某些人认识的功能强大得多.您可以自定义浏览体验,使其 ...

  7. 自助式BI工具怎么选?这款用过都说好!

    随着大数据时代的到来,很多公司的业务数据量不断增长,公司必须集中精力管理数据,并在BI工具的帮助下进行数据分析,以便从过去的数据中获得洞察力,预测未来的发展.近年来,随着企业对数据的关注度的增加,企业 ...

  8. Specified cast is not valid(C#) 引发的思考(装箱,拆箱本质)

    没有很华丽的语言,直接拿代码说事情把. 这段代码,会报错吗?  结论:当然不会 这段代码会报错了.原因是为啥? 这里面的水比较深.也要提醒各位写代码的适合要引起注意.异常:System.Invalid ...

  9. ScrollView垂直滚动和HrizontalScrollView水平滚动

    当我们在写一个页面,内容过多时我们需要滚动页面来查看,但是注意ScrollView下只能有一个元素,所以要把主页面改下,这样就只有一个LinearLayout元素: 1 <ScrollView ...

  10. 人工智能之深度学习-初始环境搭建(安装Anaconda3和TensorFlow2步骤详解)

    前言: 本篇文章主要讲解的是在学习人工智能之深度学习时所学到的知识和需要的环境配置(安装Anaconda3和TensorFlow2步骤详解),以及个人的心得体会,汇集成本篇文章,作为自己深度学习的总结 ...