最近生產環境出現一個很奇怪的問題,測試環境沒法重現,本地直連生產沒法重現。因而用上 jmap + Java VisualVM 的 OQL (Object Query Language) 分析問題。javascript
關於OGL的文章很少,特此轉載,原文出處:http://www.javashuo.com/article/p-wmjhxduj-hb.htmlcss
本文主要翻譯自JDK 1.8的JVM監控工具jhat中關於OQL的英文幫助說明。html
能夠在jhat 和 jvisualvm 中進行實踐。java
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]語法訪問數組元素
sql
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 >= 256express
/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平臺類的私有字段可能會被修改/刪除而不會發出任何通知!(實施細節)。可是,在用戶類上使用此類查詢多是安全的 - 假設用戶能夠控制類。