219.144.206.60,浏览器自动关闭,川fa8512
最近生产环境出现一个很奇怪的问题,测试环境无法重现,本地直连生产无法重现。于是用上 jmap + java visualvm 的 oql (object query language) 分析问题。
关于ogl的文章不多,特此转载,原文出处:
本文主要翻译自jdk 1.8的jvm监控工具jhat中关于oql的英文帮助说明。
可以在jhat 和 jvisualvm 中进行实践。
oql是用于查询java堆的类sql查询语言。oql允许过滤/选择从java堆中获取的信息。虽然hat已经支持预定义的查询,例如“显示类x的所有实例”,但oql增加了更多的灵活性。oql基于javascript表达式语言。
select <javascript expression to select> [ from [instanceof] <class name> <identifier> [ where <javascript boolean expression to filter> ] ]
解释:
(1)class name是java类的完全限定名,如:java.lang.string, java.util.arraylist, [c是char数组, [ljava.io.file是java.io.file[],依此类推
(2)类的完全限定名不足以唯一的辨识一个类,因为不同的classloader载入的相同的类,它们在jvm中是不同类型的
(3)instanceof表示也查询某一个类的子类,如果不明确instanceof,则只精确查询class name指定的类
(4)from和where子句都是可选的
(5)可以使用obj.field_name语法访问java字段,并且可以使用array [index]语法访问数组元素
select s from java.lang.string s where s.value.length >= 100
select a from [i a where a.length >= 256
另一种方式:select a from int[] a where a.length >= 256
/java/ 修改成你的正则表达式,如/^myclass$/ 就会匹配myclass这个字符串
select file.path.value.tostring() from java.io.file file
select classof(cl).name from instanceof java.lang.classloader cl
select o from instanceof 0x741012748 o请注意,0x741012748是类的id(在会话中)。通过查看该类页面中显示的id可以找到它。
该堆内置对象支持下列方法:
heap.foreachclass(callback);
heap.foreachobject(callback, clazz, includesubtypes);
clazz
是选择其实例的类。如果未指定,则默认为java.lang.object。includesubtypes
是一个布尔标志,指定是否包含子类型实例。该标志的默认值为true。heap.findclass(classname);where
classname
是要查找的类的名称。生成的class对象具有以下属性:
heap.findobject(stringidofobject);
heap.objects(clazz, [includesubtypes], [filter])
clazz
是选择其实例的类。如果未指定,则默认为java.lang.object。includesubtypes
是一个布尔标志,指定是否包含子类型实例。该标志的默认值为true。此方法接受可选的过滤器表达式以过滤对象的结果集。select heap.livepaths(s) from java.lang.string s该数组本身的每个元素都是另一个数组。后一个数组包含一个位于路径“引用链”中的对象。
例子:
select heap.findclass("java.lang.system").statics.props
select heap.findclass("java.lang.string").fields.length
select heap.findobject("0xf3800b58")
select filter(heap.classes(), "/java.net./.test(it.name)")
alloctrace函数
这将返回给定java对象的分配站点跟踪(如果可用)。alloctrace返回对象的数组。每个对象具有以下属性:
classof函数
返回给定java对象的class对象。结果对象支持以下属性:
类对象具有以下方法:
例子:
select classof(o).name from instanceof java.lang.ref.reference o
select heap.findclass("java.io.inputstream").subclasses()
select heap.findclass("java.io.bufferedinputstream").superclasses()
foreachreferrer函数
identical函数
返回两个给定的java对象是否相同。
select identical(heap.findclass("foo").statics.bar, heap.findclass("anotherclass").statics.bar)
objectid函数
返回给定java对象的string id。此id可以传递给 heap.findobject,也可以用于比较对象以进行标识。
select objectid(o) from java.lang.object o
reachables函数
返回从给定java对象传递引用的java对象数组。(可选)接受第二个参数,该参数是逗号分隔的字段名称,以从可达性计算中排除。字段以class_name.field_name模式编写。
例子:
select reachables(p) from java.util.properties p
referrers函数
返回引用了给定java对象的所有对象
例子:
select count(referrers(o)) from java.lang.object o
select referrers(f) from java.io.file f
select u from java.net.url u where count(referrers(u)) > 2
referees函数
返回给定java对象直接引用的java对象数组。
示例:打印java.io.file类的所有静态引用字段
select referees(heap.findclass("java.io.file"))
refers函数
返回第一个java对象是否引用第二个java对象。
root函数
如果给定对象是根对象集的成员,则此函数返回描述其原因的描述性根对象。如果给定的对象不是root,则此函数返回null。
sizeof函数
以字节为单位返回给定java对象的大小示例:
select sizeof(o) from [i o
返回给定java对象的html字符串。请注意,对于select表达式选择的对象,会自动调用此方法。但是,打印更复杂的输出可能很有用。示例:以粗体字体重量打印超链接
select "<b>" + tohtml(o) + "</b>" from java.lang.object o
可以使用javascript对象文字或数组选择多个值。
示例:显示每个线程对象的名称和线程
这些函数接受数组/迭代器/枚举和表达式字符串[或回调函数]作为输入。这些函数迭代数组/迭代器/枚举,并在每个元素上应用表达式(或函数)。请注意,javascript对象是关联数组。因此,这些函数也可以与任意javascript对象一起使用。
concat函数
连接两个数组或枚举(即返回复合枚举)。
contains函数
返回给定的数组/枚举是否包含代码中指定的给定布尔表达式的元素。评估的代码可以引用以下内置变量。
示例:选择某些静态字段引用某些类的所有properties对象。
count函数
count函数返回满足给定布尔表达式的输入数组/枚举的元素数。布尔表达式代码可以引用以下内置变量。
示例:查询匹配特定名称模式的类的数量
select count(heap.classes(), "/java.io./.test(it.name)")
filter函数
filter函数返回一个数组/枚举,其中包含满足给定布尔表达式的输入数组/枚举的元素。布尔表达式代码可以引用以下内置变量。
例子:
select filter(heap.classes(), "/java.io./.test(it.name)")
length函数返回数组/枚举的元素数。
map函数
通过评估每个元素上的给定代码来转换给定的数组/枚举。评估的代码可以引用以下内置变量。
map函数返回通过在输入数组/枚举的每个元素上重复调用代码而创建的值的数组/枚举。
示例:显示具有名称和值的java.io.file的所有静态字段
select map(heap.findclass("java.io.file").statics, "index + '=' + tohtml(it)")
max函数
返回给定数组/枚举的最大元素。(可选)接受代码表达式以比较数组的元素。默认情况下使用数字比较。比较表达式可以使用以下内置变量:
例子:
select max(map(heap.objects('java.lang.string', false), 'it.value.length'))
min函数
返回给定数组/枚举的最小元素。(可选)接受代码表达式以比较数组的元素。默认情况下使用数字比较。比较表达式可以使用以下内置变量:
例子:
select min(map(heap.objects('java.util.vector', false), 'it.elementdata.length'))
select min(heap.objects('java.util.vector'), 'lhs.elementdata.length < rhs.elementdata.length')
给出数组/枚举的排序。(可选)接受代码表达式以比较数组的元素。默认情况下使用数字比较。比较表达式可以使用以下内置变量:
例子:
select sort(heap.objects('[c'), 'sizeof(lhs) - sizeof(rhs)')
select map(sort(heap.objects('[c'), 'sizeof(lhs) - sizeof(rhs)'), '{ size: sizeof(it), obj: it }')
sum函数
此函数返回给定输入数组或枚举的所有元素的总和。(可选)接受表达式作为第二个参数。这用于在对输入元素求和之前映射输入元素。
示例:返回每个properties对象中可到达对象的大小总和
toarray函数
此函数返回一个包含输入数组/枚举元素的数组。
unique函数
此函数返回包含给定输入数组/枚举的唯一元素的数组/枚举
示例:选择从字符串引用的唯一char []实例。请注意,多个string实例可以共享内容的相同char []。
打印每个类加载器的直方图和由它加载的类的数量
select map(sort(map(heap.objects('java.lang.classloader'), '{ loader: it, count: it.classes.elementcount }'), 'lhs.count < rhs.count'), 'tohtml(it) + "<br>"')
上面的查询解释:java.lang.classloader有一个名为java.util.vector类型的类的私有字段,vector有一个名为elementcount的私有字段,它是vector中元素的数量。我们使用javascript对象文字和地图功能选择多个值(加载器,计数)。我们使用带有比较表达式的sort函数对count(即加载的类数)进行排序。
查询每个类加载器实例的父子链
select map(heap.objects('java.lang.classloader'), function (it) { var res = ''; while (it != null) { res += tohtml(it) + "->"; it = it.parent; } res += "null"; return res + "<br>"; })
请注意,我们使用java.lang.classloader类的父字段并使用回调函数遍历parent为null以映射调用。
查询所有系统属性的值
select map(filter(heap.findclass('java.lang.system').statics.props.table, 'it != null'), function (it) { var res = ""; while (it != null) { res += it.key.value.tostring() + '=' + it.value.value.tostring() + '<br>'; it = it.next; } return res; });
以上查询使用以下事实:
请注意,此查询(以及许多其他查询)可能不稳定 - 因为java平台类的私有字段可能会被修改/删除而不会发出任何通知!(实施细节)。但是,在用户类上使用此类查询可能是安全的 - 假设用户可以控制类。
如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复
浅析我对 String、StringBuilder、StringBuffer 的理解
使用IDEA搭建SSM框架的详细教程(spring + springMVC +MyBatis)
Springboot整合freemarker 404问题解决方案
引入mybatis-plus报 Invalid bound statement错误问题的解决方法
网友评论