Category: language

  • arthas常用的命令

    查询静态变量

    [arthas@174072]$ getstatic com.mulang.octopus.Main standAloneStorageNode
    field: standAloneStorageNode
    @Boolean[true]
    Affect(row-cnt:1) cost in 6 ms.
    

    使用ognl方式

    [arthas@227877]$  ognl "@java.nio.Bits@RESERVED_MEMORY"
    @AtomicLong[
        serialVersionUID=@Long[1927816293512124184],
        VM_SUPPORTS_LONG_CAS=@Boolean[true],
        U=@Unsafe[jdk.internal.misc.Unsafe@12b9a7fa],
        VALUE=@Long[16],
        value=@Long[9515349],
        serialVersionUID=@Long[-8742448824652078965],
    ]
    [arthas@227877]$
    [arthas@227877]$  ognl "@java.nio.Bits@RESERVED_MEMORY.get()"
    @Long[9515349]
    [arthas@227877]$
    

    调用没有参数的静态命令.

    #public static DataStoreType typeDataStore()
    
    [arthas@174072]$ ognl '@com.mulang.octopus.blockstore.BlockServiceProxy@typeDataStore()'
    @DataStoreType[LOCAL_DISK]
    

    调用有参数的静态命令.

    #public static long diskFreeCapacity(int serverId, int diskId) throws IOException
    
    [arthas@11123]$ ognl  '@com.mulang.octopus.blockstore.BlockServiceProxy@diskFreeCapacity(3,40001)'
    @Long[211085709312]
    

    解决方法重载

    通过制定参数个数的形式解决不同的方法签名

    tt -t *Test print params.length\=\=1
    

    通过制定参数个数的形式解决不同的方法签名,如果参数个数一样,你还可以这样写

    tt -t *Test print ‘params[1] instanceof Integer’

    解决指定参数

    tt -t *Test print params[0].mobile\=\=”13989838402″

    构成条件表达式的 Advice 对象

    表达式核心变量

    public class Advice {
    
        private final ClassLoader loader;   //本次调用类所在的 ClassLoader
        private final Class<?> clazz;       //本次调用类的 Class 引用
        private final ArthasMethod method;  //本次调用方法反射引用
        private final Object target;        //本次调用类的实例
        //本次调用参数列表,这是一个数组,如果方法是无参方法则为空数组
        private final Object[] params;
        //本次调用返回的对象。当且仅当 isReturn==true 成立时候有效,表明方法调用是以正常返回的方式结束。如果当前方法无返回值 void,则值为 null
        private final Object returnObj;
        //本次调用抛出的异常。当且仅当 isThrow==true 成立时有效,表明方法调用是以抛出异常的方式结束。
        private final Throwable throwExp;
        //辅助判断标记,当前的通知节点有可能是在方法一开始就通知,此时 isBefore==true 成立,同时 isThrow==false 和 isReturn==false,因为在方法刚开始时,还无法确定方法调用将会如何结束。
        private final boolean isBefore;
        //辅助判断标记,当前的方法调用以抛异常的形式结束。
        private final boolean isThrow;
        //辅助判断标记,当前的方法调用以正常返回的形式结束。
        private final boolean isReturn;
    
        // getter/setter
    }
    

    所有变量都可以在表达式中直接使用,如果在表达式中编写了不符合 OGNL 脚本语法或者引入了不在表格中的变量,则退出命令的执行;

    热更新某个类

    class/classloader 相关

    • classloader – 查看 classloader 的继承树,urls,类加载信息,使用 classloader 去 getResource
    • dump – dump 已加载类的 byte code 到特定目录
    • jad – 反编译指定已加载类的源码
    • mc – 内存编译器,内存编译.java文件为.class文件
    • redefine – 加载外部的.class文件,redefine 到 JVM 里
    • retransform – 加载外部的.class文件,retransform 到 JVM 里
    • sc – 查看 JVM 已加载的类信息
    • sm – 查看已加载类的方法信息
    $ retransform /tmp/MathGame.class
    retransform success, size: 1, classes:
    demo.MathGame
    
    

    Note:

    • redefine 的 class 不能修改、添加、删除类的 field 和 method,包括方法参数、方法名称及返回值
    • 如果 mc 失败,可以在本地开发环境编译好 class 文件,上传到目标系统,使用 redefine 热加载 class

    tt 和 watch

    tt

    • 需要强调的是,tt 命令是将当前环境的对象引用保存起来,但仅仅也只能保存一个引用而已。如果方法内部对入参进行了变更,或者返回的对象经过了后续的处理,那么在 tt 查看的时候将无法看到当时最准确 的值。这也是为什么 watch 命令存在的意义
    表格字段 字段解释
    INDEX 时间片段记录编号,每一个编号代表着一次调用,后续 tt 还有很多命令都是基于此编号指定记录操作,非常重要。
    TIMESTAMP 方法执行的本机时间,记录了这个时间片段所发生的本机时间
    COST(ms) 方法执行的耗时
    IS-RET 方法是否以正常返回的形式结束
    IS-EXP 方法是否以抛异常的形式结束
    OBJECT 执行对象的hashCode(),注意,曾经有人误认为是对象在 JVM 中的内存地址,但很遗憾他不是。但他能帮助你简单的标记当前执行方法的类实体
    CLASS 执行的类名
    METHOD 执行的方法名
    [arthas@15217]$ tt -t demo.MathGame primeFactors -n 3
    Press Q or Ctrl+C to abort.
    Affect(class count: 1 , method count: 1) cost in 100 ms, listenerId: 1
     INDEX       TIMESTAMP                    COST(ms)      IS-RET      IS-EXP      OBJECT                CLASS                                      METHOD
    --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
     1000        2023-03-10 03:37:42          1.419275      true        false       0x232204a1            MathGame                                   primeFactors
     1001        2023-03-10 03:37:43          0.144813      false       true        0x232204a1            MathGame                                   primeFactors
     1002        2023-03-10 03:37:44          4.481957      true        false       0x232204a1            MathGame                                   primeFactors
    Command execution times exceed limit: 3, so command will exit. You can set it with -n option.
    [arthas@15217]$ tt -t demo.MathGame primeFactors -n 2
    Press Q or Ctrl+C to abort.
    Affect(class count: 1 , method count: 1) cost in 28 ms, listenerId: 2
     INDEX       TIMESTAMP                    COST(ms)      IS-RET      IS-EXP      OBJECT                CLASS                                      METHOD
    --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
     1003        2023-03-10 03:38:15          0.128059      true        false       0x232204a1            MathGame                                   primeFactors
     1004        2023-03-10 03:38:16          0.028727      true        false       0x232204a1            MathGame                                   primeFactors
    Command execution times exceed limit: 2, so command will exit. You can set it with -n option.
    
    #list
    [arthas@15217]$ tt -l
     INDEX       TIMESTAMP                    COST(ms)      IS-RET      IS-EXP      OBJECT                CLASS                                      METHOD
    --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
     1000        2023-03-10 03:37:42          1.419275      true        false       0x232204a1            MathGame                                   primeFactors
     1001        2023-03-10 03:37:43          0.144813      false       true        0x232204a1            MathGame                                   primeFactors
     1002        2023-03-10 03:37:44          4.481957      true        false       0x232204a1            MathGame                                   primeFactors
     1003        2023-03-10 03:38:15          0.128059      true        false       0x232204a1            MathGame                                   primeFactors
     1004        2023-03-10 03:38:16          0.028727      true        false       0x232204a1            MathGame                                   primeFactors
    Affect(row-cnt:5) cost in 3 ms.
    [arthas@15217]$ tt -i 1003
     INDEX          1003
     GMT-CREATE     2023-03-10 03:38:15
     COST(ms)       0.128059
     OBJECT         0x232204a1
     CLASS          demo.MathGame
     METHOD         primeFactors
     IS-RETURN      true
     IS-EXCEPTION   false
     PARAMETERS[0]  @Integer[162701]
     RETURN-OBJ     @ArrayList[
                        @Integer[7],
                        @Integer[11],
                        @Integer[2113],
                    ]
    Affect(row-cnt:1) cost in 4 ms.
    
    #replay
    [arthas@15217]$ tt -i 1003 -p
     RE-INDEX       1003
     GMT-REPLAY     2023-03-10 04:37:14
     OBJECT         0x232204a1
     CLASS          demo.MathGame
     METHOD         primeFactors
     PARAMETERS[0]  @Integer[162701]
     IS-RETURN      true
     IS-EXCEPTION   false
     COST(ms)       0.047237
     RETURN-OBJ     @ArrayList[
                        @Integer[7],
                        @Integer[11],
                        @Integer[2113],
                    ]
    Time fragment[1003] successfully replayed 1 times.
    
  • openstack4j 开启debug模式

    // 开启debug 模式.
    OSFactory.enableHttpLoggingFilter(true);
    // V3 authentication
    OSClient.OSClientV3 os = OSFactory.builderV3().endpoint(iamDomainV3)
                    .credentials(this.getUserName(), this.getPassWord(), Identifier.byName(this.domainName))
                    .scopeToDomain(Identifier.byName(this.domainName)).perspective(Facing.PUBLIC).withConfig(config)
                    .authenticate();
    

    openstack4j 支持输出http 日志. 方便查看请求发送的参数.

  • float_and_double

    浮点数是指用符号,尾数,基数和指数这四部分来表示的小数。因为计算机内部使用的是二进制数,所以基数自然是2。

    来源

    CPU中的二进制数据(小数篇)

    计算机浮点数规格化表示

    单精度与双精度是什么意思,有什么区别?

    浮点数

    • 双进度 64 位,8byte

    • 单精度 32 位,4byte

    浮点数构成`

    浮点数构成_双精度

    浮点数构成_单精度

    1. IEEE 754標準規定:非正規形式的浮點數的指數偏移值比正規形式的浮點數的指數偏移值小1。例如,最小的正規形式的單精度浮點數的指數部分編碼值為1,指數的實際值為-126;而非規約的單精度浮點數的指數域編碼值為0,對應的指數實際值也是-126而不是-127。實際上非正規形式的浮點數仍然是有效可以使用的,只是它們的絕對值已經小於所有的規約浮點數的絕對值;即所有的非規約浮點數比規約浮點數更接近0。規約浮點數的尾數大於等於1且小於2,而非規約浮點數的尾數小於1且大於0

    2. 小数部分是原十进制数值变为二进制后再经过规格化,规格化后省去唯一的整数1之后剩下的0.0100000 00000000 00000000写进去的。

    3. 指数部分是由指数实际值-3再加上固定值(这里取IEEE754标准的固定值2**(e-1)-1,e为储存指数的比特长度,在这里是8 bit)(单精度时指数偏移度为127,目的是为了同时可以表示正和负的指数,即00000000-11111111分别对应-127 — 128)。

      # 十进制运算
      0.15625-(1.0/8)-0-(1.0/32) = 0
      # 因式分解,用二的倍数表示
      0.15625=(1.0/8)+0+(1.0/32)
      # 转为二进制
      0.15625=(1)*(0+0.00101)=(1)*(1+0.01)x2^(-3)
      # 二进制下小数位为0.01
      # 尾数为0100 0000 0000 0000 0000 000
      # 指数 -3
      (-3)-(-127)=134 => 0b0111_1100
      
      

    一个32位单精度浮点数-3.75表示的例子:

    #首先转化为2进制表示
    −3.75=−(2+1+1/2+1/4)=−1.111×2^1
    #整理符号位并进行规格化表示
    −1.111×21=(−1)(1)×(1+0.1110 0000 0000 0000 0000 000)×2^1
    # 尾数为1110 0000 0000 0000 0000 000
    # 指数为1-127=128=0b10000000
    

    精度

    浮点数的尾数是二进制的,转化之后,有一些数无法表示,这也是精度丢失的原因.

  • go 内存对齐

    文章来源

    内存对齐是指首地址对齐,而不是说每个变量大小对齐

    为减少内存对齐带来的 padding 浪费. 构建结构体时,先写大的成员

    操作系统并非一个字节一个字节访问内存,而是按2, 4, 8这样的字长来k访问。
    因此,当 CPU 从存储器读数据到寄存器,或者从寄存器写数据到存储器,IO 的数据长度通常是字长。 如:
    * 32 位系统访问粒度是 4 字节(bytes),
    * 64 位系统的是 8 字节。

    当被访问的数据长度为 n 字节且该数据地址为n字节对齐,那么操作系统就可以高效地一次定位到数据,无需多次读取、处理对齐运算等额外操作。
    数据结构应该尽可能地在自然边界上对齐。如果访问未对齐的内存,CPU 需要做两次内存访问。

    没有内存对齐,cpu读取两次,然后在寄存器中合并.

    平台对齐系数

    计算机在加载和保存数据时,如果内存地址合理地对齐的将会更有效率。
    * 2字节大小的int16类型的变量地址应该是偶数,
    * 一个4字节大小的rune类型变量的地址应该是4的倍数,
    * 一个8字节大小的float64、uint64或64-bit指针类型变量的地址应该是8字节对齐的。
    * 但是对于再大的地址对齐倍数则是不需要的,即使是complex128等较大的数据类型最多也只是8字节对齐。

    unsafe.Sizeof

    unsafe.Sizeof函数返回操作数在内存中的字节大小
    * 参数可以是任意类型的表达式
    * 并且它并不会对表达式进行求值。

    unsafe.Alignof

    unsafe.Alignof 函数返回对应参数的类型需要对齐的倍数.
    和 Sizeof 类似, Alignof 也是返回一个常量表达式, 对应一个常量.
    通常情况下布尔和数字类型需要对齐到它们本身的大小(最多8个字节), 其它的类型对齐到机器字大小.

    unsafe.Offsetof

    unsafe.Offsetof 函数的参数必须是一个字段 x.f, 然后返回 f 字段相对于 x 起始地址的偏移量, 包括可能的空洞

    go string 类型 大小 16.

    • go语言的string是一种数据类型,这个数据类型占用16字节空间,
    • 前8字节是一个指针,指向字符串值的地址,后八个字节是一个整数,标识字符串的长度;
    • 注意go语言的字符串内部并不以’\0’作为结尾,而是通过一个长度域来表示字符串的长度。

    go 数组类型, 测试过 []int8 和 []int 都是 24

    • 在Go语言中数组是一个值类型value type
    • 是真真实实的数组,而不是一个指向数组内存起始位置的指针,也不能和同类型的指针进行转化,这一点严重不同于C语言
    • 所有的值类型变量在赋值和作为参数传递时都将产生一次复制动作
      (这让我想起, channel 传递对象的时候,也是值拷贝. 需要避免拷贝巨大对象)
    • 如果将数组作为函数的参数类型,则在函数调用时该参数将发生数据复制。因此,在函数体中无法修改传入的数组的内容,因为函数内操作的只是所传入数组的一个副本。

    demo

    package main
    
    import (
        "fmt"
        "reflect"
        "unsafe"
    )
    
    type empty_struct struct {
    }
    
    type empty_struct_with_name1 struct {
        flag    bool
        name    string
        empty_s empty_struct
    }
    
    type empty_struct_with_name2 struct {
        a bool
        b empty_struct
        c string
        d empty_struct
    }
    
    func main() {
        s_val := "test"
        int_arr_val := []int{0, 1, 2, 3, 4, 5}
        var empty_s empty_struct
    
        fmt.Println("type:\t", reflect.TypeOf(s_val), "\tsize of:\t", unsafe.Sizeof(s_val), "\talign of:\t", unsafe.Alignof(s_val), "\tval:\t", s_val)
        fmt.Println("type:\t", reflect.TypeOf(int_arr_val), "\tsize of:\t", unsafe.Sizeof(int_arr_val), "\talign of:\t", unsafe.Alignof(int_arr_val), "\tval:\t", int_arr_val)
    
      //空 struct 正常size of 是 0
        fmt.Println("type:\t", reflect.TypeOf(empty_s), "\tsize of:\t", unsafe.Sizeof(empty_s), "\talign of:\t", unsafe.Alignof(empty_s), "\tval:\t", empty_s)
    
      // 空 struct 由于需要内存对齐,占了 8 字节空间
        var empty_s_name1 empty_struct_with_name1
        fmt.Println("type:\t", reflect.TypeOf(empty_s_name1), "\tsize of:\t", unsafe.Sizeof(empty_s_name1), "\talign of:\t", unsafe.Alignof(empty_s_name1), "\tval:\t", empty_s_name1)
    
      //第一个空 struct 由于需要内存对齐和 bool a 一起共同占了 8 字节空间
      //第二个空 struct 由于需要内存对齐和 独自占了 8 字节空间
        var empty_s_name2 empty_struct_with_name2
        fmt.Println("type:\t", reflect.TypeOf(empty_s_name2), "\tsize of:\t", unsafe.Sizeof(empty_s_name2), "\talign of:\t", unsafe.Alignof(empty_s_name2), "\tval:\t", empty_s_name2)
        fmt.Println("struce empty_s_name2 size of:\t", unsafe.Sizeof(empty_s_name2),
            "\ta offset of:\t", unsafe.Offsetof(empty_s_name2.a), "\tb offset of:\t", unsafe.Offsetof(empty_s_name2.b),
            "\tc offset of:\t", unsafe.Offsetof(empty_s_name2.c), "\td offset of:\t", unsafe.Offsetof(empty_s_name2.d))
    
        /*
            output :
            type:    string     size of:     16     align of:    8  val:     test
            type:    []int  size of:     24     align of:    8  val:     [0 1 2 3 4 5]
            type:    main.empty_struct  size of:     0  align of:    1  val:     {}
            type:    main.empty_struct_with_name1   size of:     32     align of:    8  val:     {false  {}}
            type:    main.empty_struct_with_name2   size of:     32     align of:    8  val:     {false {}  {}}
            struce empty_s_name2 size of:    32     a offset:    0  b offset of:     1  c offset of:     8  d offset of:     24
        */
    }