V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
rock123
V2EX  ›  Java

Java 如何监测静态变量值的变化?

  •  1
     
  •   rock123 · 90 天前 · 2367 次点击
    这是一个创建于 90 天前的主题,其中的信息可能已经有所发展或是发生改变。

    维护一个老系统,有个 Config 类,其中有个静态变量 DEBUG ,默认值为 0 ,定义如下:

    public static int DEBUG;
    

    目前正式环境这个值在某些情况下会被修改成 1 ,搜了下系统中代码调用,没发现可疑的重新赋值代码,想请教下大家,如何在不修改现有代码,不增加 setter 方法的情况下监控这个变量值,当值变化时触发一个回调,打印代码执行路径?

    第 1 条附言  ·  89 天前

    @ikas @gitdoit 感谢两位,JDI 的 ModificationWatchpointEvent 有用,非常符合我的需求,我总结了一个最简单的使用方法,供有同样需求的人使用,字数超了,使用方法总结在语雀里了

    https://www.yuque.com/docs/share/70aaa901-a2c5-4ab2-9339-e9d329d19ca1?# 《debugger》 链接有效期至 2022-04-10 12:22:33

    顺便求个免费的可分享markdown的在线工具,临时用下,语雀永久分享还要开会员

    33 条回复    2022-04-11 18:45:03 +08:00
    panpanpan
        1
    panpanpan  
       90 天前
    有趣,等一个大佬
    paragon
        2
    paragon  
       90 天前
    idea 把断点打在 field 上变化的时候就会停下
    xylophone21
        3
    xylophone21  
       90 天前
    0o0O0o0O0o
        4
    0o0O0o0O0o  
       90 天前 via iPhone
    了解不多,java 应该没办法 watch variable 吧?所以我的思路是动态替换掉这个类,以前破解 java 应用是利用 javaagent
    zhazi
        5
    zhazi  
       90 天前
    mbean?
    MakHoCheung
        6
    MakHoCheung  
       90 天前
    是不是通过反射来改掉的?
    ikas
        7
    ikas  
       90 天前
    用 java 调试相关的 api 估计可以
    jdi ModificationWatchpointEvent
    dncba
        8
    dncba  
       90 天前
    使用阿里的 阿尔萨斯 工具调试一把
    oneisall8955
        10
    oneisall8955  
       90 天前
    全局搜索 DEBUG 都没有?
    liangkang1436
        11
    liangkang1436  
       90 天前 via Android
    先配置远程调试,然后在本地的源码的属性上打断点,等进断点的时候看一下断点的调用栈即可
    rock123
        12
    rock123  
    OP
       90 天前
    @paragon #2
    @xylophone21 #3

    感谢两位

    电脑没装 eclipse ,没有测试,看了下 idea ,确实可以监控静态变量变化,把断点打在 field ,右键断点,取消勾选 suspend, Log 一行勾选 stack trace 选项,就可以在值变化时,控制台输出代码调用路径,且不阻塞代码。

    不过问题背景是线上环境偶发的一个 bug ,目前还不知道怎么触发什么时间触发,部署在远程 linux 服务器,没有图形界面。所以得我电脑全天开远程 debug ,平时电脑还有其他操作,很担心对线上服务的稳定,性能造成影响。

    最好是有办法可以在代码层面监控,再不济也得是第三方命令行工具部署服务器监控,实在没办法,我再试这个远程 debug 方式
    cpstar
        13
    cpstar  
       90 天前
    运行环境下,能重新 deploy Config 这个类么?如果能,那就重写 Config ,然后起一个线程一直输出这个值。如果不能,那没办法了。
    rock123
        14
    rock123  
    OP
       90 天前
    @dncba #8 好像没有监控变量的功能,只看到有监控方法返回值的功能。 修改这个 DEBUG 是直接 Config.DEBUG = xxx ,没有方法调用的
    AlisaDestiny
        15
    AlisaDestiny  
       90 天前 via Android
    同推荐阿里的 arthas,在线调试神器
    rock123
        16
    rock123  
    OP
       90 天前
    @cpstar #13 轮询方法不太好,因为不知道何时会触发,一直开着,时间间隔小了,日志太多,对系统也有影响,时间间隔大了,又有可能变化在时间片内,监测不到
    nothingistrue
        17
    nothingistrue  
       90 天前
    逐步骤监控变量的值还有办法,但是你想在值变化时做自动处理(打印些信息),你不动代码是不行的。这是个 public 成员,可以直接赋值,切面都加不上。

    还是想办法做断点调试吧,一步一步的查看值的变化。当然你不能直接在线上搞远程调试,尤其是你还想长时间的监控。你这个是公共静态变量,一个断点暂停就可能让整个系统崩溃。能在本地环境复现问题然后在本地断点调试是最好的,如果不能或者不好复现,那么只能逐行看代码了。

    Eclipse 有几个功能可以帮助你找到哪个代码会修改这个值:右键变量然后选择“call hierarchy”;选中变量再 Ctrl+H ,然后可以查找所有引用这个变量的地方。
    cpstar
        18
    cpstar  
       90 天前
    如果是改成写 public static final int 呢?哪里要改写,是不是会抛异常?另外在反射上,能否仍然改写呢?
    zmal
        19
    zmal  
       90 天前
    1.用 arthas 应该是可以的。
    2.把这个字段改成 final 并上线,通过流量复制手段复制线上服务请求,看报错堆栈。
    但是代码真的能复杂到通过源码找不到一个 Config 类里的 static 变量是什么情况下被改变吗?有点怀疑。
    hotcool100
        20
    hotcool100  
       90 天前
    继续找,或许在引入的 jar 里的类里面呢
    sky857412
        21
    sky857412  
       90 天前   ❤️ 1
    fxxkgw
        22
    fxxkgw  
       90 天前
    修改的地方估计被打成包了 所以单纯查关键词找不到 试试 grep 搜索下
    likeunix
        23
    likeunix  
       90 天前 via Android
    还是 C#香
    v2lf
        24
    v2lf  
       90 天前
    @cpstar 发射可以修改 final
    "final fields can be changed via reflection and other implementation-dependent means."
    但是要注意常量表达式赋值
    “If a final field is initialized to a constant expression (§15.28) in the field declaration, changes to the final field may not be observed, since uses of that final field are replaced at compile time with the value of the constant expression.”

    而且更改的话,会有线程安全问题
    v2lf
        25
    v2lf  
       90 天前
    @v2lf 可以看下 System 类
    lower
        26
    lower  
       90 天前
    @sky857412 这个好像不行,好像上还是在 setter 里面做记录……
    debuggeeker
        27
    debuggeeker  
       89 天前
    我排查诡异调用的一种方法,如果代码层面搜索不出来,那就打好包反编译找。先打个 release 的包,然后通过 jadx 或者其他反编译工具反编译一次,代码没混淆就好,反编译之后搜索这个类和熟悉的调用。如:const.debug 看看哪里使用了,又或者包名+类名全局搜索,看看哪里使用了这个类然后看属性的调用。
    Unicorns96
        28
    Unicorns96  
       89 天前
    将这个变量修饰为 final ,报异常查看堆栈就可以了
    rock123
        29
    rock123  
    OP
       89 天前
    @ikas #7

    @gitdoit #9

    感谢大佬提示,JDI 的 ModificationWatchpointEvent 有用,非常符合我的需求
    rock123
        30
    rock123  
    OP
       89 天前
    @nothingistrue #17
    @cpstar #18
    @zmal #19
    @Unicorns96 #28

    ide 的查看代码调用功能试过了,只有程序启动时赋值,其他都是读取值,bug 不知道哪里触发什么时候触发,bug 发生后,日志里变量值是不对的,当时又看了内存中的变量值,是正常的,估计是哪里有动态执行代码

    线上环境,不想随便修改旧代码,导致一些其他 bug ,所以加 final 不合适

    arthas 只能监控方法返回值,或者手动获取静态变量值,我这边需要监控静态变量值,有变化时程序主动发出通知。或许是我不会用,请指教
    aguesuka
        31
    aguesuka  
       89 天前
    BiChengfei
        32
    BiChengfei  
       85 天前
    github 就可以当 markdown
    链接失效了,重新发发看看怎么用的,我没看懂文档
    rock123
        33
    rock123  
    OP
       85 天前
    @BiChengfei #32
    主题不能追加了。 github 地址在这: https://github.com/XMrgao/jdi-demo.git
    关于   ·   帮助文档   ·   API   ·   FAQ   ·   我们的愿景   ·   广告投放   ·   感谢   ·   实用小工具   ·   1147 人在线   最高记录 5497   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 29ms · UTC 19:46 · PVG 03:46 · LAX 12:46 · JFK 15:46
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.