JVM 對象查詢語言(OQL)[轉載]

最近生產環境出現一個很奇怪的問題,測試環境沒法重現,本地直連生產沒法重現。因而用上 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(對象查詢語言) 

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]語法訪問數組元素
 sql

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 >= 256express

  • 顯示與正則表達式匹配的字符串的內容
    1.  
      select s. value.toString() from java.lang.String s
    2.  
      where /java/.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的實例
    select o from instanceof 0x741012748 o
    請注意,0x741012748是類的ID(在會話中)。經過查看該類頁面中顯​​示的id能夠找到它。


 

OQL內置對象,函數

堆對象

內置對象支持下列方法:安全

  • heap.forEachClass - 爲每一個Java類調用一個回調函數
    heap.forEachClass(callback);
  • heap.forEachObject - 爲每一個Java對象調用回調函數
    heap.forEachObject(callback, clazz, includeSubtypes);
    clazz是選擇其實例的類。若是未指定,則默認爲java.lang.Object。includeSubtypes是一個布爾標誌,指定是否包含子類型實例。該標誌的默認值爲true。
  • heap.findClass - 查找給定名稱的Java類
    heap.findClass(className);
    where 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函數

爲給定Java對象的每一個引用者調用一個回調函數。

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中的全部可訪問內容,但省略可經過指定字段訪問的對象。
  1.  
    select reachables(u, 'java.net.URL.handler') from java.net.URL u
  2.  
     

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

toHtml函數

返回給定Java對象的HTML字符串。請注意,對於select表達式選擇的對象,會自動調用此方法。可是,打印更復雜的輸出可能頗有用。示例:以粗體字體重量打印超連接

select "<b>" + toHtml(o) + "</b>" from java.lang.Object o

 

選擇多個值

可使用JavaScript對象文字或數組選擇多個值。

示例:顯示每一個線程對象的名稱和線程

  1.  
    select { name: t.name? t.name. toString() : "null", thread: t }
  2.  
    from instanceof java .lang .Thread t

 

數組/迭代器/枚舉操做函數

這些函數接受數組/迭代器/枚舉和表達式字符串[或回調函數]做爲輸入。這些函數迭代數組/迭代器/枚舉,並在每一個元素上應用表達式(或函數)。請注意,JavaScript對象是關聯數組。所以,這些函數也能夠與任意JavaScript對象一塊兒使用。

concat函數

鏈接兩個數組或枚舉(即返回複合枚舉)。

contains函數

返回給定的數組/枚舉是否包含代碼中指定的給定布爾表達式的元素。評估的代碼能夠引用如下內置變量。

  • it - >目前訪問過的元素
  • index - >當前元素的索引
  • array - >正在迭代的數組/枚舉

示例:選擇某些靜態字段引用某些類的全部Properties對象。

  1.  
    select p from java.util. Properties p
  2.  
    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對象的全部引用
    1.  
      select filter(referrers(u), "! /java.net./.test(classof(it).name)")
    2.  
      from java.net.URL u

     

length函數

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'))
  • 查找具備最大長度的字符串實例
    1.  
      select max(heap.objects('java.lang.String'), 'lhs.value.length > rhs.value.length')
    2.  
       

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')

sort函數

給出數組/枚舉的排序。(可選)接受代碼表達式以比較數組的元素。默認狀況下使用數字比較。比較表達式可使用如下內置變量:

  • 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對象中可到達對象的大小總和

  1.  
    select sum( map(reachables(p), 'sizeof(it)'))
  2.  
    from java.util.Properties p
  3.  
     
  4.  
    // or omit the map as in ...
  5.  
    select sum(reachables(p), 'sizeof(it)')
  6.  
    from java.util.Properties p

toArray函數

此函數返回一個包含輸入數組/枚舉元素的數組。

unique函數

此函數返回包含給定輸入數組/枚舉的惟一元素的數組/枚舉

示例:選擇從字符串引用的惟一char []實例。請注意,多個String實例能夠共享內容的相同char []。

  1.  
    // number of unique char[] instances referenced from any String
  2.  
    select count( unique( map(heap.objects( 'java.lang.String'), 'it.value')))
  3.  
     
  4.  
    // total number of Strings
  5.  
    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平臺類的私有字段可能會被修改/刪除而不會發出任何通知!(實施細節)。可是,在用戶類上使用此類查詢多是安全的 - 假設用戶能夠控制類。

相關文章
相關標籤/搜索