import{_ as t,o,c as r,a as s,b as e,e as n,d as i,r as l}from"./app.391b0e4e.js";const c={},p=s("h1",{id:"retransform",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#retransform","aria-hidden":"true"},"#"),n(" retransform")],-1),d={href:"https://arthas.aliyun.com/doc/arthas-tutorials?language=en&id=command-mc-retransform",target:"_blank",rel:"noopener noreferrer"},u=s("code",null,"mc-retransform",-1),m=n(" online tutorial"),h=s("div",{class:"custom-container tip"},[s("p",{class:"custom-container-title"},"TIP"),s("p",null,[n("Load the external "),s("code",null,"*.class"),n(" files to retransform the loaded classes in JVM.")])],-1),v=n("Reference: "),f={href:"https://docs.oracle.com/javase/8/docs/api/java/lang/instrument/Instrumentation.html#retransformClasses-java.lang.Class...-",target:"_blank",rel:"noopener noreferrer"},k=n("Instrumentation#retransformClasses"),b=i(`

Usage

   retransform /tmp/Test.class
   retransform -l
   retransform -d 1                    # delete retransform entry
   retransform --deleteAll             # delete all retransform entries
   retransform --classPattern demo.*   # triger retransform classes
   retransform -c 327a647b /tmp/Test.class /tmp/Test\\$Inner.class
   retransform --classLoaderClass 'sun.misc.Launcher$AppClassLoader' /tmp/Test.class

retransform the specified .class file

$ retransform /tmp/MathGame.class
retransform success, size: 1, classes:
demo.MathGame

Load the specified .class file, then parse out the class name, and then retransform the corresponding class loaded in the jvm. Every time a .class file is loaded, a retransform entry is recorded.

TIP

If retransform is executed multiple times to load the same class file, there will be multiple retransform entries.

View retransform entry

$ retransform -l
Id              ClassName       TransformCount  LoaderHash      LoaderClassName
1               demo.MathGame   1               null            null

Delete the specified retransform entry

Need to specify id:

retransform -d 1

Delete all retransform entries

retransform --deleteAll

Explicitly trigger retransform

$ retransform --classPattern demo.MathGame
retransform success, size: 1, classes:
demo.MathGame

WARNING

Note: For the same class, when there are multiple retransform entries, if retransform is explicitly triggered, the entry added last will take effect (the one with the largest id).

Eliminate the influence of retransform

If you want to eliminate the impact after performing retransform on a class, you need to:

TIP

If you do not clear all retransform entries and trigger retransform again, the retransformed classes will still take effect when arthas stop.

Use with the jad/mc command

jad --source-only com.example.demo.arthas.user.UserController > /tmp/UserController.java

mc /tmp/UserController.java -d /tmp

retransform /tmp/com/example/demo/arthas/user/UserController.class

Tips for uploading .class files to the server

The mc command may fail. You can modify the code locally, compile it, and upload it to the server. Some servers do not allow direct uploading files, you can use the base64 command to bypass.

  1. Convert the .class file to base64 first, then save it as result.txt

    Base64 < Test.class > result.txt
    
  2. Login the server, create and edit result.txt, copy the local content, paste and save

  3. Restore result.txt on the server to .class

    Base64 -d < result.txt > Test.class
    
  4. Use the md5 command to verify that the .class files are consistent.

Restrictions of the retransform command

public class MathGame {
    public static void main(String[] args) throws InterruptedException {
        MathGame game = new MathGame();
        while (true) {
            game.run();
            TimeUnit.SECONDS.sleep(1);
            // This doesn't work because the code keeps running in while
            System.out.println("in loop");
        }
    }

    public void run() throws InterruptedException {
        // This works because the run() function ends completely every time
        System.out.println("call run()");
        try {
            int number = random.nextInt();
            List<Integer> primeFactors = primeFactors(number);
            print(number, primeFactors);

        } catch (Exception e) {
            System.out.println(String.format("illegalArgumentCount:%3d, ", illegalArgumentCount) + e.getMessage());
        }
    }
}
`,30);function g(y,x){const a=l("ExternalLinkIcon");return o(),r("div",null,[p,s("p",null,[s("a",d,[u,m,e(a)])]),h,s("p",null,[v,s("a",f,[k,e(a)])]),b])}var _=t(c,[["render",g],["__file","retransform.html.vue"]]);export{_ as default};