JVM 物件查詢語言(OQL)jmap生成的dump檔案分析用到
轉自:https://blog.csdn.net/pange1991/article/details/82023771做了一些修改
本文主要翻譯自JDK 1.8的JVM監控工具jhat中關於OQL的英文幫助說明。
可以在jhat 和 jvisualvm 中進行實踐。
OQL(物件查詢語言)
OQL是用於查詢Java堆的類SQL查詢語言。OQL允許過濾/選擇從Java堆中獲取的資訊。雖然HAT已經支援預定義的查詢,例如“顯示類X的所有例項”,但OQL增加了更多的靈活性。OQL基於JavaScript表示式語言。
OQL查詢的形式
-
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]語法訪問陣列元素
OQL示例
- 查詢長度大於等於100的字串
select s from java.lang.String s where s.value.length >= 100
- 查詢長度大於等於256的int陣列
select a from [I a where a.length >= 256
另一種方式:select a from int[] a where a.length >= 256
- 顯示與正則表示式匹配的字串的內容【注意select s不要寫成select s.value.toString()否則沒有String的索引資訊了,這裡後面的s表示從型別String裡獲取值包裝成s,s.value則是String型別值,因此最後的s.value.toString()其實可以直接s.value即可
- select s from java.lang.String s
- where /pattern/.test(s.value.toString())
/java/ 修改成你的正則表示式,如/^MyClass$/ 就會匹配MyClass這個字串
- 顯示所有File物件的檔案路徑
select file.path.value.toString() from java.io.File file
- 顯示所有ClassLoader類的名稱
select classof(cl).name from instanceof java.lang.ClassLoader cl
- 顯示由給定id字串標識的Class的例項
請注意,0x741012748是類的ID(在會話中)。通過檢視該類頁面中顯示的id可以找到它。select o from instanceof 0x741012748 o
OQL內建物件,函式
堆物件
該堆內建物件支援下列方法:
- heap.forEachClass- 為每個Java類呼叫一個回撥函式
heap.forEachClass(callback);
- heap.forEachObject- 為每個Java物件呼叫回撥函式
heap.forEachObject(callback, clazz, includeSubtypes);
clazz
是選擇其例項的類。如果未指定,則預設為java.lang.Object。includeSubtypes
是一個布林標誌,指定是否包含子型別例項。該標誌的預設值為true。 - heap.findClass- 查詢給定名稱的Java類
whereheap.findClass(className);
className
是要查詢的類的名稱。生成的Class物件具有以下屬性:- name - 類的名稱。
- superclass - 超類的類物件(如果是java.lang.Object,則為null)。
- statics - 類的靜態欄位的名稱,值對。
- fields - 欄位物件的陣列。field物件具有名稱,簽名屬性。
- loader - 載入此類的ClassLoader物件。
- signers - 簽署此類的簽名者。
- protectionDomain - 此類所屬的保護域。
- isSubclassOf - 測試給定的類是否是此類的直接或間接子類。
- isSuperclassOf - 測試給定的Class是否是此類的直接或間接超類。
- subclasses - 返回直接和間接子類的陣列。
- superclasses - 返回直接和間接超類的陣列。
- heap.findObject- 從給定的物件id中查詢物件
heap.findObject(stringIdOfObject);
- heap.classes- 返回所有Java類的列舉
- heap.objects- 返回Java物件的列舉
heap.objects(clazz, [includeSubtypes], [filter])
clazz
是選擇其例項的類。如果未指定,則預設為java.lang.Object。includeSubtypes
是一個布林標誌,指定是否包含子型別例項。該標誌的預設值為true。此方法接受可選的過濾器表示式以過濾物件的結果集。 - heap.finalizables- 返回待完成的Java物件的列舉。
- heap.livepaths- 返回給定物件存活的路徑陣列。此方法接受可選的第二個引數,它是一個布林標誌。此標誌指示是否包含弱引用的路徑。預設情況下,不包括具有弱引用的路徑。
該陣列本身的每個元素都是另一個數組。後一個數組包含一個位於路徑“引用鏈”中的物件。select heap.livepaths(s) from java.lang.String s
- heap.roots- 返回堆的根的列舉。每個Root物件都具有以下屬性:
- id - 此根引用的物件的字串id
- type - 描述型別的Root(JNI Global,JNI Local,Java Static等)
- description - Root的字串描述
- referrer - 負責此根或null的Thread Object或Class物件
例子:
- 訪問類java.lang.System的靜態欄位'props'
select heap.findClass("java.lang.System").statics.props
- 獲取java.lang.String類的欄位數
select heap.findClass("java.lang.String").fields.length
- 找到其物件id被賦予的物件
select heap.findObject("0xf3800b58")
- 選擇所有匹配java.net.*的類
select filter(heap.classes(), "/java.net./.test(it.name)")
單個物件上的函式
- allocTrace(jobject)
- classof(jobject)
- forEachReferrer(callback, jobject)
- identical(o1, o2)
- objectid(jobject)
- reachables(jobject, excludedFields)
- referrers(jobject)
- referees(jobject)
- refers(jobject)
- root(jobject)
- sizeof(jobject)
- toHtml(obj)
allocTrace函式
這將返回給定Java物件的分配站點跟蹤(如果可用)。allocTrace返回物件的陣列。每個物件具有以下屬性:
- className - 其方法在框架中執行的Java類的名稱。
- methodName - 執行的Java方法的名稱。
- methodSignature - 框架中執行的Java方法的簽名。
- sourceFileName - 框架中執行的Java類的原始檔的名稱。
- lineNumber - 方法中的源行號。
classof函式
返回給定Java物件的Class物件。結果物件支援以下屬性:
- name - 類的名稱。
- superclass - 超類的類物件(如果是java.lang.Object,則為null)。
- 靜態 - 類的靜態欄位的名稱,值對。
- fields - 欄位物件的陣列。欄位物件具有名稱,簽名屬性。
- loader - 載入此類的ClassLoader物件。
- 簽名者 - 簽署此類的簽名者。
- protectionDomain - 此類所屬的保護域。
類物件具有以下方法:
- isSubclassOf - 測試給定的類是否是此類的直接或間接子類。
- isSuperclassOf - 測試給定的Class是否是此類的直接或間接超類。
- subclasses - 返回直接和間接子類的陣列。
- superclasses - 返回直接和間接超類的陣列。
例子:
- 顯示每個Reference型別物件的類名
select classof(o).name from instanceof java.lang.ref.Reference o
- 顯示java.io.InputStream的所有子類
select heap.findClass("java.io.InputStream").subclasses()
- 顯示java.io.BufferedInputStream的所有超類
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模式編寫。
例子:
- 從每個Properties例項列印所有可到達的物件。
select reachables(p) from java.util.Properties p
- 列印每個java.net.URL中的所有可訪問內容,但省略可通過指定欄位訪問的物件。
select reachables(u, 'java.net.URL.handler') from java.net.URL u
referrers函式
返回引用了給定Java物件的所有物件
例子:
- 查詢每個java.lang.Object例項被引用的次數
select count(referrers(o)) from java.lang.Object o
- 查詢那些物件引用了java.io.File例項物件
select referrers(f) from java.io.File f
- 查詢被引用次數超過2的URL物件
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物件文字或陣列選擇多個值。
示例:顯示每個執行緒物件的名稱和執行緒
- select { name: t.name? t.name.toString() : "null", thread: t }
- from instanceof java.lang.Thread t
陣列/迭代器/列舉操作函式
這些函式接受陣列/迭代器/列舉和表示式字串[或回撥函式]作為輸入。這些函式迭代陣列/迭代器/列舉,並在每個元素上應用表示式(或函式)。請注意,JavaScript物件是關聯陣列。因此,這些函式也可以與任意JavaScript物件一起使用。
concat函式
連線兩個陣列或列舉(即返回複合列舉)。
contains函式
返回給定的陣列/列舉是否包含程式碼中指定的給定布林表示式的元素。評估的程式碼可以引用以下內建變數。
- it - >目前訪問過的元素
- index - >當前元素的索引
- array - >正在迭代的陣列/列舉
示例:選擇某些靜態欄位引用某些類的所有Properties物件。
- select p from java.util.Properties p
- where contains(referrers(p), "classof(it).name == 'java.lang.Class'")
- concat(array1/enumeration1, array2/enumeration2)
- contains(array/enumeration, expression)
- count(array/enumeration, expression)
- filter(array/enumeration, expression)
- length(array/enumeration)
- map(array/enumeration, expression)
- max(array/enumeration, [expression])
- min(array/enumeration, [expression])
- sort(array/enumeration, [expression])
- sum(array/enumeration, [expression])
- toArray(array/enumeration)
- unique(array/enumeration, [expression])
count函式
count函式返回滿足給定布林表示式的輸入陣列/列舉的元素數。布林表示式程式碼可以引用以下內建變數。
- it- >目前訪問過的元素
- index - >當前元素的索引
- array - >正在迭代的陣列/列舉
示例:查詢匹配特定名稱模式的類的數量
select count(heap.classes(), "/java.io./.test(it.name)")
filter函式
filter函式返回一個數組/列舉,其中包含滿足給定布林表示式的輸入陣列/列舉的元素。布林表示式程式碼可以引用以下內建變數。
- it - >目前訪問過的元素
- index - >當前元素的索引
- array - >正在迭代的陣列/列舉
- result - > result array / enumeration
例子:
- 顯示所有具有匹配java.io. * 的類
select filter(heap.classes(), "/java.io./.test(it.name)")
- 顯示引用者不是來自java.net包的URL物件的所有引用
- select filter(referrers(u), "! /java.net./.test(classof(it).name)")
- from java.net.URL u
length函式返回陣列/列舉的元素數。
map函式
通過評估每個元素上的給定程式碼來轉換給定的陣列/列舉。評估的程式碼可以引用以下內建變數。
- it - >目前訪問過的元素
- index - >當前元素的索引
- array - >正在迭代的陣列/列舉
- result - > result array / enumeration
map函式返回通過在輸入陣列/列舉的每個元素上重複呼叫程式碼而建立的值的陣列/列舉。
示例:顯示具有名稱和值的java.io.File的所有靜態欄位
select map(heap.findClass("java.io.File").statics, "index + '=' + toHtml(it)")
max函式
返回給定陣列/列舉的最大元素。(可選)接受程式碼表達式以比較陣列的元素。預設情況下使用數字比較。比較表示式可以使用以下內建變數:
- lhs - >左側元素進行比較
- rhs - >右側元素進行比較
例子:
- 找到任何String例項的最大長度
select max(map(heap.objects('java.lang.String', false), 'it.value.length'))
- 查詢具有最大長度的字串例項
select max(heap.objects('java.lang.String'), 'lhs.value.length > rhs.value.length')
min函式
返回給定陣列/列舉的最小元素。(可選)接受程式碼表達式以比較陣列的元素。預設情況下使用數字比較。比較表示式可以使用以下內建變數:
- lhs - >左側元素進行比較
- rhs - >右側元素進行比較
例子:
- 找到任何Vector例項的最小大小
select min(map(heap.objects('java.util.Vector', false), 'it.elementData.length'))
- 找到具有最大長度的Vector例項
select min(heap.objects('java.util.Vector'), 'lhs.elementData.length < rhs.elementData.length')
給出陣列/列舉的排序。(可選)接受程式碼表達式以比較陣列的元素。預設情況下使用數字比較。比較表示式可以使用以下內建變數:
- lhs - >左側元素進行比較
- rhs - >右側元素進行比較
例子:
- 按大小順序列印所有char []物件。
select sort(heap.objects('[C'), 'sizeof(lhs) - sizeof(rhs)')
- 按大小順序列印所有char []物件,同時也列印大小。
select map(sort(heap.objects('[C'), 'sizeof(lhs) - sizeof(rhs)'), '{ size: sizeof(it), obj: it }')
sum函式
此函式返回給定輸入陣列或列舉的所有元素的總和。(可選)接受表示式作為第二個引數。這用於在對輸入元素求和之前對映輸入元素。
示例:返回每個Properties物件中可到達物件的大小總和
- select sum(map(reachables(p), 'sizeof(it)'))
- from java.util.Properties p
- // or omit the map as in ...
- select sum(reachables(p), 'sizeof(it)')
- from java.util.Properties p
toArray函式
此函式返回一個包含輸入陣列/列舉元素的陣列。
unique函式
此函式返回包含給定輸入陣列/列舉的唯一元素的陣列/列舉
示例:選擇從字串引用的唯一char []例項。請注意,多個String例項可以共享內容的相同char []。
- // number of unique char[] instances referenced from any String
- select count(unique(map(heap.objects('java.lang.String'), 'it.value')))
- // total number of Strings
- select count(heap.objects('java.lang.String'))
更復雜的例子
列印每個類載入器的直方圖和由它載入的類的數量
- 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.lang.System具有型別為java.util.Properties的名稱為'props'的靜態欄位。
- java.util.Properties的欄位為'table',型別為java.util.Hashtable $ Entry(此欄位繼承自java.util.Hashtable)。這是hashtable桶陣列。
- java.util.Hashtable $ Entry包含'key','value'和'next'欄位。每個條目指向同一雜湊表桶中的下一個條目(或null)。
- java.lang.String類具有char []型別的'value'欄位。
請注意,此查詢(以及許多其他查詢)可能不穩定 - 因為Java平臺類的私有欄位可能會被修改/刪除而不會發出任何通知!(實施細節)。但是,在使用者類上使用此類查詢可能是安全的 - 假設使用者可以控制類