`
beck5859509
  • 浏览: 111264 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

ASM

 
阅读更多
/bin/zsh -c "$(curl -fsSL https://gitee.com/cunkai/HomebrewCN/raw/master/Homebrew.sh)"于公司jvm智能分析平台的思考

引子
在讲述主题之前,先看一下之前遇到的几个问题
1、问题一
2、问题二
3、问题三
url1
url2
url3


目前公司缺少一个jvm智能分析平台,在遇到一些比较难定位的问题时,往往只能查看日志,或者临时添加日志,但也会带来一些麻烦,比如日志量过大,进程重启问题不必现等,又或者只能反复jstack进行问题猜测,但效果也不理想。

jvm智能分析平台的特点。
1、动态加载,目标程序无需重启
2、字节码编程、性能得到保障
3、web平台化操作
3、目标方法的入参、异常、返回结果的分析
4、目标方法内部每一行代码的hao时的分析
5、指定java实例数统计及size分析
3、与第三方jar进行隔离,代码无污染
4、对线程栈做快照对线程

demo展示

冰山一角

可行性
已和运维组勇哥沟通,并无相关的平台,只是简单的组件的监控

相关技术
/java/jni/jvmti/bytecode/c/c++



1、统计指定的java实例数,并可以统计每个实例的大小(size)
2、查找最高耗时的方法(小型程序)
3、拉取git代码进行web在线调试
4、采集到与JVM 有关的大量信息,例如内存、线程、JVM 崩溃等
5、对线程栈做快照
6、Java Agent受jvm本身的影响

总结
Native Agent因为工作原理的不同,导致其与Java Agent相比,拥有明显的优势,具体总结如下:
1. 获取JVM运行时的性能参数。
2. 获取JVM线程方法调用栈信息
3. 不受JVM的运行状态影响。
4. 开销更少

visitAnnotationDefault?
( visitAnnotation | visitParameterAnnotation | visitAttribute )*
( visitCode
( visitTryCatchBlock | visitLabel | visitFrame | visitXxxInsn |
visitLocalVariable | visitLineNumber )*
visitMaxs )?
visitEnd


Btrace (Byte Trace)是sun推出的一款Java 动态、安全追踪(监控)工具,可以在不停机的情况下监控系统运行情况,并且做到最少的侵入,占用最少的系统资源。。BTrace在使用上做了很多限制,如不能创建对象、不能使用数组、不能抛出或捕获异常、不能使用循环、不能使用synchronized关键字、脚本的属性和方法都必须使用static修饰等,具体限制条件可参考用户手册。根据官方声明,不当地使用BTrace可能导致JVM崩溃,如BTrace使用错误的.class文件,所以,可以先在本地验证BTrace脚本的正确性再使用



https://blog.csdn.net/coslay/article/details/43113029
https://www.cnblogs.com/163yun/p/10078137.html

asm:
0:   aload_0
首先第一个0代表虚指令中的行号(后面会应到,确切说应该是方法的body部分第几个字节),每个方法从0开始顺序递增,但是可以跳跃,跳跃的原因在于一些指令还会接操作的内容,这些操作的内容可能来自常量池,也可以标志是第几个slot的本地变量,因此需要占用一定的空间。

aload_0指令是将“第1个”slot所在的本地变量推到栈顶,并且这个本地变量是引用类型的,相关的指令有:aload_[0-3](范围是:0x2a ~ 0x2d)。如果超过4个,则会使用“aload + 本地变量的slot位置”来完成(此时会多占用1个字节来存放),前者是通过具体的几个指令直接完成。

许多地方会解释为第1个引用类型的本地变量,但胖哥是一个逻辑怪,认为这句话有问题,并不是第1个引用变量,普通变量如果在它之前,它也不是第1个了,此时本身就是第1个本地变量,更确切地说是第一个slot所在位置的本地变量。



注意:

常量池的存放内容

存放所有的方法名

field名

方法签名(方法参数+返回值)

类型名

class文件中的常量值

常量池的前四部分可以称作是符号引用(即只有一些名称,但没有实际的地址,在运行期进行类的加载过后,会为这些东西分配实际的内存,到时候符号引用就会转化为直接引用,就能被JVM用了)

常量池的组成:符号引用、常量(这个常量包含我们代码中定义的常量,eg、字符串常量,也包括class文件中的常量,eg.SourceFile)。

主版本号的对应(eg.50对应jdk6,51对应jdk7),查看《深入理解java虚拟机(第二版)》P167

Stack:操作数栈的深度(这个值就是类加载阶段为操作数栈分配的深度)

Locals:局部变量的分配空间(单位是slot,不是个数),对于double和long这两个64bit的,需要两个slot,对于其他<=32bit的,只需要一个slot

Args_size:方法参数的个数,包括方法参数、this(this只针对实例方法,static方法不会自动添加this)

inc()方法:我详细注释了该方法的执行过程,这也就是JVM执行一个方法的基本流程(基于栈)


ClassReader.java

        // visits the class declaration
        classVisitor.visit(readInt(items[1] - 7), access, name, signature,
                superClass, interfaces);

        // visits the source and debug info
        if ((flags & SKIP_DEBUG) == 0
                && (sourceFile != null || sourceDebug != null)) {
            classVisitor.visitSource(sourceFile, sourceDebug);
        }

        // visits the module info and associated attributes
        if (module != 0) {
            readModule(classVisitor, context, module,
                    moduleMainClass, packages);
        }
       
        // visits the outer class
        if (enclosingOwner != null) {
            classVisitor.visitOuterClass(enclosingOwner, enclosingName,
                    enclosingDesc);
        }

        // visits the class annotations and type annotations
        if (anns != 0) {
            for (int i = readUnsignedShort(anns), v = anns + 2; i > 0; --i) {
                v = readAnnotationValues(v + 2, c, true,
                        classVisitor.visitAnnotation(readUTF8(v, c), true));
            }
        }
        if (ianns != 0) {
            for (int i = readUnsignedShort(ianns), v = ianns + 2; i > 0; --i) {
                v = readAnnotationValues(v + 2, c, true,
                        classVisitor.visitAnnotation(readUTF8(v, c), false));
            }
        }
        if (tanns != 0) {
            for (int i = readUnsignedShort(tanns), v = tanns + 2; i > 0; --i) {
                v = readAnnotationTarget(context, v);
                v = readAnnotationValues(v + 2, c, true,
                        classVisitor.visitTypeAnnotation(context.typeRef,
                                context.typePath, readUTF8(v, c), true));
            }
        }
        if (itanns != 0) {
            for (int i = readUnsignedShort(itanns), v = itanns + 2; i > 0; --i) {
                v = readAnnotationTarget(context, v);
                v = readAnnotationValues(v + 2, c, true,
                        classVisitor.visitTypeAnnotation(context.typeRef,
                                context.typePath, readUTF8(v, c), false));
            }
        }

        // visits the attributes
        while (attributes != null) {
            Attribute attr = attributes.next;
            attributes.next = null;
            classVisitor.visitAttribute(attributes);
            attributes = attr;
        }

        // visits the inner classes
        if (innerClasses != 0) {
            int v = innerClasses + 2;
            for (int i = readUnsignedShort(innerClasses); i > 0; --i) {
                classVisitor.visitInnerClass(readClass(v, c),
                        readClass(v + 2, c), readUTF8(v + 4, c),
                        readUnsignedShort(v + 6));
                v += 8;
            }
        }

        // visits the fields and methods
        u = header + 10 + 2 * interfaces.length;
        for (int i = readUnsignedShort(u - 2); i > 0; --i) {
            u = readField(classVisitor, context, u);
        }
        u += 2;
        for (int i = readUnsignedShort(u - 2); i > 0; --i) {
            u = readMethod(classVisitor, context, u);
        }

        // visits the end of the class
        classVisitor.visitEnd();



























引子



    在正式讲述本文主题前,先看一下之前项目中遇到的几个问题



    问题一

        问题现象:18年12月底的时候线上有一台手机在 18:00~21:00之间频繁连接和断开连接

        分析步骤:

        1、客户端同事初步分析手机日志,发现有断开异常,看调用堆栈是业务代码抛出

        image.png



        2、联想到后台主动关闭连接时,不会写入mqtt 消息,所以输入流stream读不到数据属于正常现象。

             另外问题发生时的日志已经被清除,只能查看客户端的其它日志,幸运的是当时有网络包可以分析

        3、查看网络请求终于发现一些端倪:

            image.png

            image.png

            客户端先是连接101.132.150.36,同时后台139.196.100.216断开客户端连接(18:00:53前的连接),18:01分客户端又继续连接139.196.100.216,形成循环连接的现象。

            重点查看连接connack的返回结果,找到了突破口。

            image.png

         4、第二个红框值为3,代表需要重新注册。因个别手机在多用户场景会出现连接切换重连的情况,后台发现token不匹配就会进行重连,客户端已经针对此情况修复。



    问题二

        问题现象:5月初收到ups-receiver线程池任务队列阻塞的监控报警

        分析步骤:

        1、查看错误日志,并没有找到相应的线索,也没有异常的日志。

        2、因为当天凌晨12点半发现,临时重启解决问题。

        3、对比内外部的receiver,单独拆分了回执线程池处理,并发布上线观察。

        4、果然第二天问题还是出现,打印jstack进行分析。

        5、问题得到确认,回执写入mq时的线程被阻塞,联系中间件同事进行处理,问题得以解决。

            image.png



    其它烧脑问题

    http://km.vivo.xyz/pages/viewpage.action?pageId=28500755

    http://km.vivo.xyz/pages/viewpage.action?pageId=16279250

    http://km.vivo.xyz/pages/viewpage.action?pageId=14488732



    当前痛点:

     梳理以上问题时都存在一个共同特点,业务在遇到一些比较难定位的问题时,往往只能查看日志,或者临时添加日志,但这也会带来一些麻烦,比如日志量过大,

     进程重启问题不必现,需要临时发布版本(可能引入其它风险)等,或者只能反复jstack进行问题猜测,但效果都不理想。当然针对不同层次需求场景,有对应

     的工具,比如内存占用过多,得不到释放,可以dump出文件,但是分析此文件也并不容易,有一定的成本。还有类似jconsole等工具,但已有的这些工具并不能

     满足高级的应用场景,比如动态查看方法的入参/返回结果/某个成员变量的值就可以很快定位出问题。



     解决方案:

        一个比较好的解决方案是建设一个公司级的JVM智能分析平台 --- 开发人员可以根据不同场景输入参数快速定位问题,提前监测,并协助智能分析问题发生的根因。

        jvm智能分析平台具备以下特点。

        1、动态加载,目标程序无需重启

        2、字节码编程、性能得到保障

        3、web平台化操作

        4、对目标方法的入参、异常、返回结果的分析

        5、对目标方法内部代码的耗时的分析

        6、对指定java实例数统计及size分析

        7、与第三方jar进行隔离,代码无污染

        8、对线程堆栈智能分析可能的问题原因



   冰山一角

    jdk1.5以后,jdk整合了一套有关虚拟机的JVMTI接口,可以供使用者调用,JVMTI的功能非常丰富,包含了访问虚拟机中线程/内存/堆/栈/类/方法/变量的方法。

    开发者可以灵活使用这些特性,开发出很多高级功能,比如上述提到的功能,不过这些接口是C/C++的,实现起来有一定的难度。以下例举两个例子。



    例一:

    比如下面展示了一个比较有趣的例子---通过java类名查找进程中对应实例的数量,具本如下。

    1、java端的统计调用功能由一个本地方法实现,通过jni的方式嵌入jvm中,具体实现通过c++代码去实现

    image.png

  

    2、监控程序启动时开启jvm统计对象数的功能

    image.png

    3、使用jvmit的方法迭代对象size及实例个数

    image.png

    4、最终结果,已之前java代码预期一致

    image.png



    除了通过jvmti实现上述功能(实现成本偏高),jdk还提供了instrument技术,可通过字节码转换进行实现相同的功能,并且功能更强大,

    除了实现监测,还可以动态添加新的功能:)



    例二:

    这里例举给目标方法动态添加try/catch及一个局部变量int i = 20的例子,当然也可以增加耗时统计

    1、Student类中最初的say方法

    image.png

    编译后Student的say方法字节码:

    image.png

    2、对目标方法进行添加字节码(部分代码)

    image.png

    3、编译后say方法的字节码

    image.png

   

    查看上图汇编后的字节码文件,istore_1已经将栈顶的int值20保存到了局部变量中,并且增加了try/catch的异常捕获

    总结:字节码编程方式同样可以动态实现目标程序的变更,但底层也通过jvmti进行实现的,但是通过字节码简单化了jvmti的开发工作量,当然为了更好的理解

              是有必要同时掌握jvmti指令及字节码指定的。以上只是字节码编程的冰山一角,这里不展开介绍了。



    以下是 jvm智能分析平台架构图



   image.png   



    该系统后期还可以衍生其它更强大的功能:比如通过web端拉取git代码在线调试线上环境(支付宝目前已有类似的功能)

 

    成本:

        关于系统人力评估(正式加两个外包-前端和后端各一人)

    收益 :

        1、智能分析系统,提前发现疑难、隐藏较深的问题,减少线上问题造成的损失。

        2、节省定位问题成本,现在项目越来越多,系统逻辑也越来越复杂,通过该系统快速锁定问题原因。
分享到:
评论

相关推荐

    asm-2.2.3.jar,asm-commons-2.2.3.jar,asm-util-2.2.3.jar

    ASM是一个强大的Java字节码操控和分析框架,它可以直接生成和修改Java类和注解的字节码。这个框架主要用于动态代理、代码分析以及优化等场景。在Java开发中,当我们需要在运行时生成或者修改类的行为时,ASM提供了一...

    asm.jar各个版本

    asm-1.3.3.jar, asm-1.3.4.jar, asm-1.3.5.jar, asm-1.4.1.jar, asm-1.4.2.jar, asm-1.4.3.jar, asm-1.4.jar, asm-1.5.1.jar, asm-1.5.2.jar, asm-1.5.3.jar, asm-2.0.jar, asm-2.1.jar, asm-2.2.1-sources.jar, asm...

    1、ASM1064 DATASHEET; 2、ASM1064 参考原理图设计; 3、支持的SPI Flash清单

    ASM1064是一款高性能的PCI Express to SATA 3.0桥接芯片,由ASMIC公司设计制造。这款芯片主要用于实现PCI Express接口与SATA接口之间的数据高速传输,广泛应用于存储扩展卡、固态硬盘控制器等领域。以下是关于ASM...

    redhat/centos6.9 kmod-oracleasm/oracleasm-support/oracleasm rpm包

    kmod-oracleasm-2.0.8-15.el6_9.x86_64 oracleasm-support-2.1.8-1.el6.x86_64 oracleasmlib-2.0.4-1.el6.x86_64 安装顺序: rpm -ivh kmod-oracleasm-2.0.8-15.el6_9.x86_64.rpm rpm -ivh oracleasm-support-2.1.8...

    ASM 1351.zip

    ASM 1351 是一款由ASMedia( ASM 微电子)公司开发的集成电路,主要应用于数据传输和接口控制领域。这个压缩包“ASM 1351.zip”包含了与ASM 1351相关的三个关键文件:一个固件升级工具、数据表以及设计套件。 1. **...

    cglib-2.2.jar asm-tree.jar asm-commons.jar asm.jar

    【标题】"cglib-2.2.jar asm-tree.jar asm-commons.jar asm.jar" 提供的是一组用于Java编程的库,它们主要用于实现动态代理和字节码操作。 【描述】"cglib动态代理模式jar包 cglib-2.2.jar asm-tree.jar asm-...

    EditPlus(附asm.acp,asm.stx)

    ASM文件的扩展名通常为`.asm`,它允许程序员对计算机硬件进行精确控制,尽管相比高级语言,学习曲线较为陡峭,但在某些特定场景,如系统编程或优化代码时,汇编语言显得尤为重要。 【asm.acp】和【asm.stx】是...

    asm 6.0 工具集

    这套工具包括了ASM、ASM-Util、ASM-TREE和ASM-ANALYSIS等组件,每个都有其特定的功能和用途。 **ASM库**是核心部分,提供低级别的API来生成和解析Java字节码。ASM库允许开发者直接操作字节码,创建和修改类,甚至在...

    asm-util.jar

    asm-util-1.3.4.jar, asm-util-1.3.5.jar, asm-util-1.4.1.jar, asm-util-1.4.3.jar, asm-util-1.5.1.jar, asm-util-1.5.2.jar, asm-util-1.5.3.jar, asm-util-2.0.jar, asm-util-2.1.jar, asm-util-2.2.1-sources....

    各种oracleasm rpm包(Linux下配置ASM使用)

    包含如下oracleasm包: kmod-oracleasm-2.0.6.rh1-3.el6.x86_64.rpm oracleasm-2.0.8-4.el6_6.src.rpm oracleasm-2.0.8-6.el6_7.src.rpm oracleasm-2.0.8-8.el7.src.rpm oracleasm-2.0.8-15.el7.centos.src.rpm ...

    ASM1061.zip

    ASM1061是一款由ASMtek(Asmedia Technology Inc.)公司生产的高性能PCI Express (PCIe) to Serial Advanced Technology Attachment (SATA)桥接芯片,主要用于扩展计算机系统的SATA接口,使得硬件开发人员能够轻松地...

    asm操作指南(中文)

    ### asm操作指南(中文)知识点总结 #### 一、ASM框架简介 - **定义与功能**:ASM是一个Java字节码操纵框架,主要用于动态生成类或增强现有类的功能。通过直接生成二进制`.class`文件,ASM能够在类被加载到Java...

    stm32duino/ASM330LHH

    在本案例中,我们关注的是ASM330LHH,这是一款高性能的三轴加速度计和三轴陀螺仪传感器,由意法半导体(STMicroelectronics)制造。ASM330LHH广泛应用于运动检测、航姿参考系统、手势识别以及物联网设备中的动态平衡...

    FIDO UAF ASM 接口文档

    ### FIDO UAF框架中ASM API详解 #### 1. 概述 FIDO (Fast IDentity Online) 是一种开放协议,旨在减少对密码的依赖并提供更安全的身份验证方式。UAF (Universal Authentication Framework) 是FIDO联盟推出的一个...

    ASM1083 PCIe转PCI芯片数据表

    ASM1083 PCIe转PCI芯片数据表 ASM1083 PCIe转PCI芯片数据表是ASMedia TECHNOLOGY INC.公司出品的一款PCIe转PCI桥接芯片,其主要功能是将PCI Express(Peripheral Component Interconnect Express)接口转换为传统的...

    asm 最新版手册

    ASM 是一个 Java 字节码操控框架。它能被用来动态生成类或者增强既有类的功能。ASM 可以直接产生二进制 class 文件,也可以在类被加载入 Java 虚拟机之前动态改变类行为。Java class 被存储在严格格式定义的 .class ...

    汇编插件 asm-dude, 支持 Visual Studio 2022

    **汇编插件 AsmDude 用于 Visual Studio 2022** AsmDude 是一款专为Visual Studio 2022设计的汇编语言插件,它极大地提升了开发人员在使用汇编语言时的工作效率和代码质量。这款插件对新手极其友好,即使是编程经验...

    ASM使用指南-中文版

    ASM是一个强大的Java字节码操控和分析框架,它允许开发者动态生成或修改Java类和运行时的类。这个“ASM使用指南-中文版”提供了全面的教程和参考信息,帮助开发者深入理解并有效地利用ASM库。 ASM的核心功能在于...

    C-include-ASM.zip_asm中include asm_c语言中嵌套asm

    在标题提到的"C-include-ASM.zip_asm中include_asm_c语言中嵌套asm",我们主要讨论的是如何在C程序中使用汇编代码,并且可能涉及到如何在汇编代码中包含其他汇编模块。 首先,让我们了解一下C语言嵌套汇编的基本...

    Oracle12c 实战ASM磁盘组管理

    ### Oracle12c 实战ASM磁盘组管理 #### 知识点概述 本文将详细介绍Oracle12c中关于ASM(Automatic Storage Management)磁盘组管理的关键知识点,包括磁盘组属性的理解与配置、创建磁盘组的过程及注意事项。 #### ...

Global site tag (gtag.js) - Google Analytics