Btrace探索&OQL测试char占用大小
Btrace探索&OQL测试char占用大小
准备工作
以下都在jvisualvm上运行,windows上可能会装插件,如图所示,在工具-插件中,可以在线装,把可用插件中能装的都装上吧!
Btrace
被测试的java代码
public class BTraceTest { public static void main(String[] args) {
while (true) {
asfqwteaf(1);
}
}
public static void asfqwteaf(int v) {
System.out.println(System.currentTimeMillis());
try {
Thread.sleep(new Random().nextInt(5) * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
测试1:监控方法执行用时
Btrace.java
/* BTrace Script Template */import com.sun.btrace.annotations.*;
import static com.sun.btrace.BTraceUtils.*;
@BTrace
public class TracingScript {
/* put your code here */
@TLS
private static long startTime = 0;
// class参数或者method参数用/exp/包裹到内容的采用正则表达式
@OnMethod(clazz = "/com.+BTraceTest/",
method = "asfqwteaf")
public static void startMethod() {
startTime = timeMillis();
}
@SuppressWarnings("deprecation")
@OnMethod(clazz = "/com.+BTraceTest/",
method = "asfqwteaf",
location = @Location(Kind.RETURN))
public static void endMethod() {
print(strcat(strcat(name(probeClass()), "."),probeMethod()));
print(" [");
print(strcat("Time taken: ", str(timeMillis() - startTime)));
println("]");
}
}
windows上直接在jvisualvm上运行就好,如图所示,点击后会出现代码输入框,输入以上代码执行就好。
运行结果
linux机器上可以装btrace插件,执行以下命令,这个我就不演示了。
btrace 9284 Btrace.java
测试2:定时执行&在代码运行某一行时执行
Btrace.java
/* BTrace Script Template */import com.sun.btrace.annotations.*;
import static com.sun.btrace.BTraceUtils.*;
@BTrace
public class TracingScript {
/* put your code here */
// class参数或者method参数用/exp/包裹到内容的采用正则表达式
@OnMethod(clazz = "/com.+BTraceTest/",
location = @Location(value=Kind.LINE, line=25))
public static void online(@ProbeClassName String pcn ,@ProbeMethodName String pmn, int line){
print(Strings.strcat(pcn,"."));
print(Strings.strcat(pmn,"."));
println(line);
}
// 每1000ms运行一次,打印vm的运行时间
@OnTimer(1000)
public static void getUpTime(){
println(Strings.strcat("1000 msec: ", Strings.str(Sys.VM.vmUptime())));
}
}
运行结果
关于Btrace的还有其他一部分东西,总体来讲不是太多,网上也有一些博客。
详细可以去github上学习:点这里进入github的Btrace
在以上github上samples文件夹下包含了所有的 demo,这里列举的demo只是点点而已。但是在本人的测试下,有一部分确实不能够正常执行(我的环境jdk1.8),难道是该技术太老了?搜了一下,网上也没有太多关于Btrace的博客。喜欢的朋友自行搞一下吧,还是有一定乐趣所在的。
OQL(Object Query Language)
说到OQL,这他娘的可真是个好东西,不要以为现在有了jprofile,MAT等等一系列内存分析工具,这东西感觉好像没啥用处了哦。当然,jvisualvm用这个还会挺顺溜的。
我们在分析dump文件的时候就可以使用这家伙。
jhat
第一个使用的地方就是jhat生成的html文件,不过这个不掩饰了,给下命令。
# 第一步,dump堆快照,当然,懒的也可以直接jvisualvm里头dump,点点点就可以jmap -dump:live,file=dump.hprof <pid>
# 第二步,jhat生成html,-JXmx512M指定对大小,当然也可以不指定
jhat -J-Xmx512M dump.hprof
jhat指令会解析dump.hprof文件,并启动一个web server,端口是7000.
来嘛,给大佬上个图:
打开页面,拉到页面最底部,看吧:
找到用的地方就行了,我不在这儿玩儿,我去jvisualVM玩儿。
jvisualVM
在界面上直接dump一个快照我就不说了,直接打开这个快照,然后点击OQL控制台,这个地方就是执行OQL的。至于OQL的详细介绍就烦请各位大佬自己去相关文档吧,跟sql有点相同语法,还是挺容易懂的,只是比较难记住而已(百度就当是手册吧,挺不错的,哈哈),小弟就不在此班门弄斧了。这里的重点是利用OQL来看一下char究竟是占用的多少字节。
检验方式: String底层是char,因此我们就采用查询String类型字符的深堆大小来看。每增长一个字符,查看深堆(rsizeof)占用的增长。由于浅堆(sizeof)不包含内容,所以同一个类型的浅堆大小都是一样的,我们就不看浅堆了,但是我会把浅堆大小给打出来,仅供欣赏。
sizeof 浅堆,rsizeof 深堆,具体可以查看OQL的相关资料。
先看一下类,其中a,aa和aaa字符串分别是一个字符,两个字符和三个中文字符。这里英文采用ISO8859-1编码是因为网上看了很多说采用这个编码的话char是占用一个字节,这里顺便验证一下是否是对的。
public class Aaa { private String a;
private String aa;
private String aaa;
public Aaa() {
try {
this.a = new String("a".getBytes("ISO8859-1"),"ISO-8859-1");
this.aa = new String("aa".getBytes("ISO8859-1"),"ISO-8859-1");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
this.aaa = "中文的";
}
}
启动类,不要误会,类名和上面Btrace测试时相同的,改了main方法而已,将就着看吧。
public class BTraceTest { private static Aaa a = new Aaa();
private static Aaa b = new Aaa();
public static void main(String[] args) throws Exception{
while (true) {
Thread.sleep(10000);
}
}
}
通过visualvm中堆dump后,打开dump文件,执行OQL查询结果。
贴一下OQL:
select {ins:s,size:sizeof(s),rsize:rsizeof(s)} from java.lang.String s where (s.toString()=="a" || s.toString()=="aa" || s.toString()=="中文的")稍微提一下,select后面的json串是规定结果输出的格式而已,sizeof(obj)打印obj的浅堆,rsizeof(obj)打印obj的深堆,s就是查询的字符串的值。看输出结果吧,,很容易懂的。
执行结果:
结果json:
{ size = 28,
ins = java.lang.String#159 - a,
rsize = 54
}
{
size = 28,
ins = java.lang.String#160 - aa,
rsize = 56
}
{
size = 28,
ins = java.lang.String#161 - 中文的,
rsize = 58
}
从结果中课看到size都是28字节,这个是浅堆。
rsize大小分别为54,56,58字节,也就是说“a”->“aa”,增加了2个字节,“aa”->“中文的”增加了2个字节。除掉char占用的字节之外,离引用28字节还差不少,这个部分是String对象其他的内容占用的。
因此可以看出ISO8859-1编码并没有什么卵用。每增加一个字符,占用的一个char都是2个字节。
最后,我们来看一下这个Aaa对象的信息。
select {ins:s,size:sizeof(s),rsize:rsizeof(s)} from com.xxx.Aaa s where (s.a.toString()=="a")
看输出(这里就不贴图了,直接复制了输出),浅堆为40,这个大小会根据它所持有的属性多少动态改变,可以自测。
{ size = 40,
ins = com.jumei.jls.common.Aaa#1,
rsize = 150
}
来个一整个的吧,输出格式json有点长,怕让各位大佬受惊没有一下子给出来,这里贴出来了。
select {ins:s,size:sizeof(s),rsize:rsizeof(s),filed:{a:{value: s.a.toString(),size:sizeof(s.a),rsize:rsizeof(s.a)},aa:{value: s.aa.toString(),size:sizeof(s.aa),rsize:rsizeof(s.aa)},aaa:{value: s.aaa.toString(),size:sizeof(s.aaa),rsize:rsizeof(s.aaa)}}} from com.jumei.jls.common.Aaa s
select中的json部分,格式化过后的:
{ ins:s,
size:sizeof(s),
rsize:rsizeof(s),
filed:{
a:{
value: s.a.toString(),
size:sizeof(s.a),
rsize:rsizeof(s.a)
},
aa:{
value: s.aa.toString(),
size:sizeof(s.aa),
rsize:rsizeof(s.aa)
},
aaa:{
value: s.aaa.toString(),
size:sizeof(s.aaa),
rsize:rsizeof(s.aaa)
}
}
}
输出结果:
{ size = 40,
filed = {
a = {
value = a,
size = 28,
rsize = 54
},
aa = {
value = aa,
size = 28,
rsize = 56
},
aaa = {
value = 中文的,
size = 28,
rsize = 58
}
},
ins = com.jumei.jls.common.Aaa#1,
rsize = 150
}
最后,小弟在此给各位大佬推荐《Java程序性能优化 葛一鸣》这本书,怎么说呢,秀啊!
over~~~
以上是 Btrace探索&OQL测试char占用大小 的全部内容, 来源链接: utcz.com/z/511966.html