java btrace asm_Java调优系列之工具篇之btrace、gperftools

Java调优系列之工具篇之btrace、gperftools

landon 网络游戏资深服务器架构师

2018-06-14

线上遇到了问题?

服务上线出问题,想增加打印日志怎么办?

线上怀疑某个接口慢,想打印接口耗时怎么办?

线上某个接口报错,想看看调用的参数和谁调用了怎么办?

线上出错了,想看某个对象的数据怎么办?

线上出错了,想看一下jvm的一些信息怎么办?

不确定线上某一行代码执行了怎么办?

......

传统解决方案

修改源代码 -> 增加相关打印日志 -> hotswap

Thread.dumpStack

beanshell可以查看内存数据

jvm信息可以通过jvm内置命令去获取

缺点

代码侵入式

不灵活

源代码冗余

如果你的服务不支持hotswap呢?

什么是btrace

BTrace is a safe, dynamic tracing tool for the Java platform.

BTrace can be used to dynamically trace a running Java program (similar to DTrace for OpenSolaris applications and OS). BTrace dynamically instruments the classes of the target application to inject tracing code ("bytecode tracing").

江南白衣

Btrace是神器,每一个需要每天解决线上问题,但完全不用Btrace的工程师,都是可疑的

btrace基础

下载

bin 加入环境变量

build 实现包和依赖包

samples 示例脚本

docs 帮助文档

基础使用

IDE下编写btrace脚本

jps找到运行的java进程pid

btrace pid btracescript

btrace脚本编写基础事项

IDE编写要引入依赖jar

btrace-agent.jar

btrace-boot.jar

btrace-client.jar

脚本就是一个.java源文件

@BTrace注解

trace的class要用full name

只能使用btrace提供的方法,不能自己随意调用(保证性能不受影响,trace才更放心)

btrace实战

一个简单的偏游戏业务的sample

btrace

Locate 定位trace的方法

Intercept 对定位到的方法进行拦截

Print 打印需要的数据

典型场景

找出最耗时的业务方法

打印调用堆栈

......

btrace#locate

TraceLocate.java

举例

@OnMethod(clazz = "/practice./", method = "/./")

@OnMethod(clazz = "+practice.IHandler", method = "/.*/")

@OnMethod(clazz = "/practice.*/", method = "@practice.LogicMethod")

@OnMethod(clazz = "/practice.*/", method = "")

看示例代码

btrace#intercept

TraceIntercept.java

举例

@OnMethod(clazz = "practice.LoginHandler", method = "login", location = @Location(Kind.ENTRY))

@OnMethod(clazz = "practice.LoginHandler", method = "login", location = @Location(Kind.RETURN))

@OnMethod(clazz = "+practice.IHandler", method = "/.*/", location = @Location(Kind.THROW))

@OnMethod(clazz = "practice.LoginHandler", method = "login", location = @Location(value = Kind.CALL, clazz = "/./", method = "/./", where = Where.AFTER))

@OnMethod(clazz = "practice.HeroHandler", method = "starUp", location = @Location(value = Kind.LINE, line = 16))

看示例代码

btrace#print

TracePrint.java

举例

printMethodSignature

AnyType

Field field = BTraceUtils.field("practice.PlayerService", "playerMap")

@TLS thread local share

看示例代码

btrace#TypicalScenes

TraceTypicalScenes.java

举例

@Duration long duration

纳秒

Kind.RETURN

BTraceUtils.jstack

OnTimer

jvm

jinfo/jmap/...

sizeof/deadlock

示例代码和自带sample

btrace原理

Client(Java compile api + attach api) + Agent(脚本解析引擎 + ASM + JDK6 Instumentation) + Socket

java attach api附加agent.jar + 脚本解析引擎+asm来重写指定类的字节码 + instrument实现对原有类的替换

通过JVM Attach API,btrace把自己绑进了被监控的进程 -> 按照脚本定义 -> AOP代码植入

btrace原理图解

cff037edb750?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

image

btrace注意的问题

限制

为了保证性能不受影响,Btrace不允许调用任何实例方法,必须使用btrace提供的api

BTrace植入过的代码,会一直在

属于“事后工具” ,即服务已经上线了,无法再通过打印日志等方式埋点分析

无法trace native

一定要用IDE写btrace脚本

其他

有一些脚本细节需要自行体会 如追踪异常的上下文

可以远程、可用于线上生成环境 还有许多其他命令参数如指定文件输出

其他工具和参考

gperftools

场景

主要分析Java的堆外内存泄露

Java进程占用内存

Note that the JVM uses more memory than just the heap. For example Java methods, thread stacks and native handles are allocated in memory separate from the heap, as well as JVM internal data structures

堆外内存

jni

nio direct buffer

gperftools#install

install

Perftools was developed and tested on x86 Linux systems, and it works in its full generality only on those systems. However, we've successfully ported much of the tcmalloc library to FreeBSD, Solaris x86, and Darwin (Mac OS X) x86 and ppc; and we've ported the basic functionality in tcmalloc_minimal to Windows. See INSTALL for details.See README_windows.txt for details on the Windows port.

强烈建议直接在linux安装,mac文档少,windows不考虑

linux注意问题

if you use a 64-bit system, we strongly recommend you install libunwind before trying to configure or install gperftools

动态库配置(ld.so.conf.d/ldconfig)、root

堆外内存泄露sample

NonHeapLeakExample.java

java.util.zip.Deflater

javac -> jar -> run.sh

javac NonHeapLeakExample.java

jar cvf NonHeapLeak.jar NonHeapLeakExample.class

java -cp ./NonHeapLeak.jar NonHeapLeakExample

top/jmap/jstat

示例代码和脚本

gperftools排查

java启动脚本增加参数

export LD_PRELOAD=/usr/local/lib/libtcmalloc.so

export HEAPPROFILE=/tmp/nonheapleak

启动输出

Starting tracking the heap

查看heap是否生成

$ ll /tmp | grep .heap

-rw-rw-r-- 1 playcrab playcrab 1048574 Jun 13 16:24 nonheapleak_28759.0001.heap

分析heap

pprof --text $JAVA_HOME/bin/java /tmp/nonheapleak_28759.0001.heap

gperftools结果展示

结果展示

Using local file /data/home/user00/playcrab/usr/jdk/bin/java.

Using local file /tmp/nonheapleak_28759.0003.heap.

Total: 300.2 MB

281.9 93.9% 93.9% 281.9 93.9% deflateInit2_

17.7 5.9% 99.8% 17.7 5.9% os::malloc@907360

0.3 0.1% 99.9% 0.3 0.1% readCEN

0.1 0.0% 100.0% 282.0 94.0% Java_java_util_zip_Deflater_init

......

分析

Java_java_util_zip_Deflater_init是一个jni方法 对应java方法

可以看到这块占用内存占用很大

如何找到谁调用了Deflater?

btrace派上用场

@OnMethod(clazz = "java.util.zip.Deflater", method = "")

public static void traceStack() {

BTraceUtils.jstack();

}

有了Java的调用堆栈,就好办了

原因

deflater没有调用end

deflater的底层实现全部是调用jni

只申请了内存但是没有释放

源代码

Q & A

演示过程中,貌似gperftools的heap没生成,进程kill的时候生成了

可以生成 不过得等一下

从输出看 是差不多6分钟左右 heap文件才生成

$ date

2018年 06月 14日 星期四 22:39:43 CST

[playcrab@achilles landon]$ sh nonHeapLeak.sh

$ ll /tmp/*.heap

-rw-rw-r-- 1 playcrab playcrab 1048562 6月 14 22:45 /tmp/nonheapleak_10821.0001.heap

-rw-rw-r-- 1 playcrab playcrab 1048563 6月 14 22:51 /tmp/nonheapleak_10821.0002.heap

关于btrace的注入问题

1. btrace注入的代码确实一直都在

2. 没有办法移除 因为再次写脚本也是在注入后的基础上

3. 通常来说线上排查问题 我们不会写如定位线上所有的业务方法都进行拦截 肯定会有选择性的 另外和源代码增加日志一样 不会有什么性能问题

4. btraceutils.println是直接发送到了attach的agent的buff(socket)没什么问题,client退出了就不会发了,只不过代码还依然执行而已 landon-本质还是socket通讯

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值