在生产环境中经常遇到格式各样的问题,如OOM或者莫名其妙的进程死掉。一般情况下是通过修改程序,添加打印日志;然后重新发布程序来完成。然而,这不仅麻烦,而且带来很多不可控的因素。有没有一种方式,在不修改原有运行程序的情况下获取运行时的数据信息呢?如方法参数、返回值、全局变量、堆栈信息等。Btrace就是这样一个工具,它可以在不修改原有代码的情况下动态地追踪java运行程序,通过hotswap技术,动态将跟踪字节码注入到运行类中,对运行代码侵入较小,对性能上的影响可以忽略不计。

基础说明

由于Btrace会把脚本逻辑直接侵入到运行的代码中,所以在使用上做很多限制:

  • 不能创建对象
  • 不能使用数组
  • 不能抛出或捕获异常
  • 不能使用循环
  • 不能使用synchronized关键字
  • 属性和方法必须使用static修饰

需要特别注意的是:不恰当的使用BTrace可能导致JVM崩溃,如在BTrace脚本使用错误的class文件,所以在上生产环境之前,务必在本地充分的验证脚本的正确性。

Btrace可以做什么?

  • 接口性能变慢,分析每个方法的耗时情况;
  • 当在Map中插入大量数据,分析其扩容情况;
  • 分析哪个方法调用了System.gc(),调用栈如何;
  • 执行某个方法抛出异常时,分析运行时参数;
  • ....

参数说明:

指定分析方法的入口:@OnMethod

Btrace使用@OnMethod注解定义需要分析的方法入口

@OnMethod注解中,需要指定class、method以及location等,class表明需要监控的类,method表明需要监控的方法,指定方式如下:

  • 使用全限定名:clazz="com.metty.rpc.common.BtraceCase", method="add"
  • 使用正则表达式:clazz="/javax.swing../", method="/./"
  • 使用接口:clazz="+com.ctrip.demo.Filter", method="doFilter"
  • 使用注解:clazz="@javax.jws.WebService", method=""@javax.jws.WebMethod"
  • 如果需要分析构造方法,需要指定method=""

指定方法拦截的位置:@Location

定义Btrace对方法的拦截位置,通过@Location注解指定,默认为Kind.ENTRY

  • Kind.ENTRY:在进入方法时,调用Btrace脚本
  • Kind.RETURN:方法执行完时,调用Btrace脚本,只有把拦截位置定义为Kind.RETURN,才能获取方法的返回结果@Return和执行时间@Duration
  • Kind.CALL:分析方法中调用其它方法的执行情况,比如在execute方法中,想获取add方法的执行耗时,必须把where设置成Where.AFTER
  • Kind.LINE:通过设置line,可以监控代码是否执行到指定的位置
  • Kind.ERROR, Kind.THROW, Kind.CATCH

总结

Btrace能做的事情太多,但使用之前切记检查脚本的可行性,一旦Btrace脚本侵入到系统中,只有通过重启才能恢复。


通过jvisualvm插件的方式进行测试:

安装Btrace插件

工具-->插件-->可用插件中找到BTrace Workbench进行安装即可。

测试用例

package com.vmtools;

public class Counter {
// 总数
private static int totalCount = 0; public int add(int num) throws Exception {
totalCount += num;
sleep(); return totalCount;
} private void sleep() throws InterruptedException {
Thread.sleep(1000);
}
}
package com.vmtools;

import java.util.Random;
public class BtraceTest { public static void main(String[] args) throws Exception { Random random = new Random(); // 计数器
Counter counter = new Counter();
while (true) {
// 每次增加随机值
counter.add(random.nextInt(10));
Thread.sleep(1000);
}
}
}

Btrace测试

运行上诉测试用例

jvisualvm中找到对应的进程id-->Trace application...-->分别进行相应的测试

获取add()方法参数值和返回值。

/* BTrace Script Template */
import com.sun.btrace.annotations.*;
import static com.sun.btrace.BTraceUtils.*; //获取add()方法参数值和返回值。
@BTrace
public class TracingScript {
/* put your code here */
@OnMethod(
clazz="com.vmtools.Counter",
method="add",
location=@Location(Kind.RETURN)
) public static void func(
int a,
@Return int result) {
println("trace: =======================");
jstack();
println(strcat("a:", str(a)));
println(strcat("result:", str(result)));
}
}

定时获取Counter类的属性值totalCount

/* BTrace Script Template */
import com.sun.btrace.annotations.*;
import static com.sun.btrace.BTraceUtils.*; //定时获取Counter类的属性值totalCount。
@BTrace
public class TracingScript {
private static Object totalCount=0; /* put your code here */
@OnMethod(
clazz="com.vmtools.Counter",
method="add",
location=@Location(Kind.RETURN)
)
public static void func(@Self com.vmtools.Counter counter) {
totalCount = get(field("com.vmtools.Counter", "totalCount"), counter);
} @OnTimer(2000)
public static void print(){
println(" ====== ");
println(strcat("totalCount: ",str(totalCount)));
}
}

获取add方法执行时间

/* BTrace Script Template */
import com.sun.btrace.annotations.*;
import static com.sun.btrace.BTraceUtils.*; //获取add方法执行时间
@BTrace
public class TracingScript {
@TLS private static long startTime = 0; /* put your code here */
@OnMethod(
clazz="com.vmtools.Counter",
method="add"
)
public static void func(@Self com.vmtools.Counter counter) {
startTime = timeNanos();
} @OnMethod(
clazz="com.vmtools.Counter",
method="add",
location=@Location(Kind.RETURN)
)
public static void endExecute(@Duration long duration){
long time = timeNanos() - startTime;
println(strcat("execute time(nanos): ", str(time)));
println(strcat("duration(nanos): ", str(duration)));
}
}

参考文档:

java性能调优及问题追踪--Btrace的使用的更多相关文章

  1. Java性能调优笔记

    Java性能调优笔记 调优步骤:衡量系统现状.设定调优目标.寻找性能瓶颈.性能调优.衡量是否到达目标(如果未到达目标,需重新寻找性能瓶颈).性能调优结束. 寻找性能瓶颈 性能瓶颈的表象:资源消耗过多. ...

  2. Java性能调优(一):调优的流程和程序性能分析

     https://blog.csdn.net/Oeljeklaus/article/details/80656732 Java性能调优 随着应用的数据量不断的增加,系统的反应一般会越来越慢,这个时候我 ...

  3. Java性能调优:利用JMC分析性能

    Java性能调优作为大型分布式系统提供高性能服务的必修课,其重要性不言而喻. 好的分析工具能起到事半功倍的效果,利用分析利器JMC.JFR,可以实现性能问题的准确定位. 本文主要阐述如何利用JMC分析 ...

  4. Java性能调优:利用JFR生成性能日志

    Java性能调优作为大型分布式系统提供高性能服务的必修课,其重要性不言而喻. 好的分析工具能起到事半功倍的效果,利用分析利器JMC.JFR,可以实现性能问题的准确定位. 本文主要阐述如何利用JFR生成 ...

  5. 第六章 Java性能调优工具(待续)

    Java性能调优工具 Windows工具 JDK命令行工具 JConsole工具 Visual VM多合一工具 Visual VM对QQL的支持 MAT内存分析工具 MAT对QQL的支持 JProfi ...

  6. java 性能调优和GC

    JAVA 性能调优和GC http://blog.csdn.net/gzh0222/article/details/7663181 JAVA GC调优手记 http://blog.csdn.net/f ...

  7. Java性能调优概述

    目录 Java性能调优概述 性能优化有风险和弊端,性能调优必须有明确的目标,不要为了调优而调优!!!盲目调优,风险远大于收益!!! 程序性能的主要表现点 执行速度:程序的反映是否迅速,响应时间是否足够 ...

  8. Java性能调优攻略全分享,5步搞定!(附超全技能图谱)

    对于很多研发人员来说,Java 性能调优都是很头疼的问题,为什么这么说?如今,一个简单的系统就囊括了应用程序.数据库.容器.操作系统.网络等技术,线上一旦出现性能问题,就可能要你协调多方面组件去进行优 ...

  9. Java性能调优实战,覆盖80%以上调优场景

    Java 性能调优对于每一个奋战在开发一线的技术人来说,随着系统访问量的增加.代码的臃肿,各种性能问题便会层出不穷. 日渐复杂的系统,错综复杂的性能调优,都对Java工程师的技术广度和技术深度提出了更 ...

随机推荐

  1. C/C++ 标准输入输出重定向

    转载自:http://www.cnblogs.com/hjslovewcl/archive/2011/01/10/2314356.html 这个对经常在OJ上做题的童鞋们很有用.OJ基本都是用标准输入 ...

  2. VLC 资料整理

    libvlc_media_t的创建 创建libvlc_media_t有两种方法:libvlc_media_new_path()和libvlc_media_new_location().简单描述一下这两 ...

  3. P2特征(一)

    很多人在提到项目的特征,肯定能说出来很多的内容,但是在英国体系下,项目的特点有哪些呢?这些特点引深的内容又有什么深度的含义.         项目具有临时性:很多人都知道项目是临时的,结束了就团队成员 ...

  4. 大数据量冲击下Windows网卡异常分析定位

    背景 mqtt的服务端ActiveMQ在windows上,多台PC机客户端不停地向MQ发送消息. 现象 观察MQ自己的日志data/activemq.log里显示,TCP链接皆异常断开.此时尝试从服务 ...

  5. django进阶

    路由系统 简而言之,django的路由系统作用就是使views里面处理数据的函数与请求的url建立映射关系.使请求到来之后,根据urls.py里的关系条目,去查找到与请求对应的处理方法,从而返回给客户 ...

  6. supermap布局设定地图网格及布局网格

    地图网格设定 LayoutElements elements = m_mapLayoutControl.MapLayout.Elements; //构造GeoMap GeoMap geoMap = n ...

  7. 【mysql】mysql 常用建表语句

    [1]建立员工档案表要求字段:员工员工编号,员工姓名,性别,工资,email,入职时间,部门.[2]合理选择数据类型及字段修饰符,要求有NOT NULL,auto_increment, primary ...

  8. PHP中的全局变量global和$GLOBALS的区别

    1.global Global的作用是定义全局变量,但是这个全局变量不是应用于整个网站,而是应用于当前页面,包括include或require的所有文件. 但是在函数体内定义的global变量,函数体 ...

  9. js控制文本框只能输入中文、英文、数字与指定特殊符号.

    先在'' 里输入 onkeyup="value=value.replace(/[^\X]/g,'')" 然后在(/[\X]/g,'')里的 X换成你想输入的代码就可以了, 中文u4 ...

  10. Nginx if 条件判断

    Nginx if 条件判断: 1.公司网站上线有这样的需求: 由于公司网站域名从http到https的转移,在测试阶段需要公司内部进行测试,公司内部局域网访问时强制访问加密的https服务,外部用户访 ...