MAT(Eclipse Memory Analyzer Tool)进阶

568 阅读4分钟

OQL查询语言

使用OQL可以对复杂的对象进行内容提取,例如做了2级缓存时,想要核对内存中的缓存和Redis是否一致时就需要OQL,方便后续的统计分析。

List数据类型

以下面的ArrayList类型的数据为例,右键Copy -> OQL Query,会自动为剪贴板一个查询语句SELECT * FROM OBJECTS 4045754,在这个语句的基础上进行查询。其中elementData[0:-1]用来对数组类型数据进行展开,然后在外层返回RosVo对象的数组,可以直接AS加别名(不能省略),通过.的方式来获取值。

需要注意的是,OQL不支持在table[0:-1]展开数组数据时直接进行数据的获取,所有的查询全部需要嵌套子查询来实现

SELECT toString(data.ruleId) FROM OBJECTS ( SELECT elementData[0:-1] AS data FROM OBJECTS 4045754 )

image.png

Map数据类型

以上一篇文章的Fact对象举例:

SELECT toString(n.key), toString(n.value) FROM OBJECTS ( SELECT OBJECTS table.@referenceArray FROM OBJECTS ( SELECT OBJECTS values FROM ".*Fact" ) ) n
# 带条件查询
SELECT toString(n.key), toString(n.value) FROM OBJECTS ( SELECT OBJECTS table.@referenceArray FROM OBJECTS ( SELECT OBJECTS values FROM ".*Fact" ) ) n WHERE (toString(n.key) = "metric_value")

image.png

Map、List、Set嵌套

我的应用中有一个较为复杂的对象CepExecutorCache,其中定义了一个静态成员变量 Map<String, List<Map<String, Map<String, Map<String, Set<String>>>>>> instanceMap = new ConcurrentHashMap<>()

SELECT toString(k1), toString(k2), toString(k3), toString(t.key), t.value FROM OBJECTS ( SELECT k AS k1, key AS k2, t.key AS k3, t.value.map.table[0:-1] AS t FROM OBJECTS ( SELECT k, key, t.key, t.value.table[0:-1] AS t FROM OBJECTS ( SELECT k AS k, t.key AS key, t.value.table[0:-1] AS t FROM OBJECTS ( SELECT key AS k, val.table[0:-1] AS t FROM OBJECTS ( SELECT d.key AS key, d.val[0:-1] AS val FROM OBJECTS ( SELECT OBJECTS c[0:-1] FROM OBJECTS ( SELECT OBJECTS instanceMap FROM OBJECTS ".*.CepExecutorCache" ) c ) d ) ) ) ) )

image.png

单个Map数据

由于Map存在hash冲突的时候会给链表添加数据,即Map的next属性,所以有事需要多次进行查询,此处简单说明

# 最外层ObjectId
SELECT k FROM OBJECTS ( SELECT toString(t.key) AS k FROM OBJECTS ( SELECT table[0:-1] AS t FROM OBJECTS 2323754  )  ) WHERE (k != "null")

# 里层1-6SELECT k FROM OBJECTS ( SELECT toString(t1.key) AS k FROM OBJECTS ( SELECT t.next.next.next.next.next.next AS t1 FROM OBJECTS ( SELECT table[0:-1] AS t FROM OBJECTS 2323754  )  )  ) WHERE (k != "null")

# 最外层数量
# 2323754为objectTags对象,copy OQL
SELECT k, toString(t1.key), t1.value FROM OBJECTS ( SELECT toString(t.key) AS k, t.value.table[0:-1] AS t1 FROM OBJECTS ( SELECT table[0:-1] AS t FROM OBJECTS 2323754  )  ) WHERE (toString(t1.key) != "null")

#控制里层next数量为1-6层的数据
SELECT k, toString(t.key), t.value FROM OBJECTS ( SELECT toString(t1.key) AS k, t1.value.table[0:-1] AS t FROM OBJECTS ( SELECT t.next.next.next.next.next.next AS t1 FROM OBJECTS ( SELECT table[0:-1] AS t FROM OBJECTS 2323754  )  )  ) WHERE (toString(t.key) != "null")

堆内存分代对象查询

新生代、s0、老年代的地址信息可以在GC日志中找到,通过日志的地址来调整OQL查询语句。 例如以下GC日志片段:

Heap after GC invocations=3572 (full 13):
 PSYoungGen      total 1275904K, used 142080K [0x0000000740000000, 0x00000007c0000000, 0x00000007c0000000)
  eden space 1133568K, 0% used [0x0000000740000000,0x0000000740000000,0x0000000785300000)
  from space 142336K, 99% used [0x0000000785300000,0x000000078ddc0130,0x000000078de00000)
  to   space 497152K, 0% used [0x00000007a1a80000,0x00000007a1a80000,0x00000007c0000000)
 ParOldGen       total 4194304K, used 2480450K [0x0000000640000000, 0x0000000740000000, 0x0000000740000000)
  object space 4194304K, 59% used [0x0000000640000000,0x00000006d7650838,0x0000000740000000)
 Metaspace       used 1137502K, capacity 1225308K, committed 1226200K, reserved 2107392K
  class space    used 146701K, capacity 169040K, committed 169176K, reserved 1048576K
}
# 新生代
SELECT * FROM instanceof "java.lang.Object" t WHERE toHex(t.@objectAddress) <= "0x7c0000000" AND toHex(t.@objectAddress) >= "0x740000000"
# s0fromSELECT * FROM instanceof "java.lang.Object" t WHERE toHex(t.@objectAddress) <= "0x785300000" AND toHex(t.@objectAddress) >= "0x740000000"
# 老年代
SELECT * FROM instanceof "java.lang.Object" t WHERE toHex(t.@objectAddress) <= "0x740000000" AND toHex(t.@objectAddress) >= "0x640000000"