<p>OQL查com.example.order.Order是否存活,需用SELECT * FROM INSTANCEOF com.example.order.Order,因类可能被多个ClassLoader加载;若无结果则对象已回收或未加载。</p>

用 OQL 查 com.example.order.Order 是否还存活,关键看 classloader 和引用链
直接写 SELECT * FROM com.example.order.Order 很可能查不到——不是对象不存在,而是类名没匹配上。JVM 中同一个类名可能由不同 ClassLoader 加载多次(比如 Spring Boot 的 LaunchedURLClassLoader、Tomcat 的 WebappClassLoader),OQL 默认只查当前上下文能解析到的那个类实例。更稳妥的方式是加 INSTANCEOF 并配合包路径模糊过滤:
-
SELECT * FROM INSTANCEOF com.example.order.Order—— 覆盖所有子类和同名类实例 - 如果仍为空,说明该类对象已被 GC 回收,或根本没加载过;若返回结果但数量极少,需结合
WHERE obj.status == "PENDING"等业务字段进一步筛选(前提是字段可访问) - OQL 不支持反射式字段访问,
obj.getStatus()会报错,只能用obj.status直接读取 public 或包级字段
jhat 启动后 OQL 查询入口在哪、怎么输才不报错
jhat 启动成功后,默认监听 http://localhost:7000,但 OQL 页面藏得比较深:不是首页的 “Show heap histogram”,也不是 “System Properties”,而是点击顶部导航栏的 OQL Query 标签页。输入框里不能带分号,不能换行,也不能用中文引号。
- 正确写法:
SELECT * FROM com.example.user.User WHERE obj.id > 100000 - 错误写法:
SELECT * FROM com.example.user.User WHERE obj.id > 100000;(结尾分号触发语法错误) - 字符串值必须用英文单引号:
WHERE obj.type == 'VIP',双引号或无引号都会被当成变量名解析失败 - 查询超时默认 30 秒,大堆(>4GB)建议先用
LIMIT 100控制返回量,避免浏览器卡死
为什么 SELECT * FROM [C 能查 char 数组,但 SELECT * FROM java.lang.String 查不到对应实例
因为 java.lang.String 对象本身不直接持有字符数据,它的 value 字段指向一个 [C(char 数组)。OQL 中的 [C 是 JVM 内部数组类型标识符,而 java.lang.String 是普通类,二者在堆中是分离存储的。想定位“内容含敏感词”的字符串,得两步走:
- 先查数组:
SELECT s FROM [C s WHERE toString(s) LIKE "*password*"(注意:toString()是 OQL 内置函数,仅对数组有效) - 再反查引用者:
SELECT OBJECTS s.@referent FROM java.lang.String s WHERE s.value == '<result-from-previous-query>'</result-from-previous-query>(依赖 jhat 的对象引用映射能力) - 别指望
LIKE支持正则,它只认*和?通配符,且大小写敏感
在 MAT 中写 OQL 和在 jhat 里写的区别,哪些语法会失效
MAT 的 OQL 引擎比 jhat 更强,但也更严格:它不支持 toString()、length 这类伪属性,也不识别 @referent 这种 jhat 特有字段。最常踩的坑是字段访问权限——MAT 只暴露 public 字段,而 jhat 默认可读包级字段(取决于 dump 时 JVM 的安全策略)。
- MAT 中要查集合大小,得用
obj.list.size,不能写obj.list.length(后者是数组语法) -
jhat允许SELECT * FROM java.util.ArrayList WHERE obj.elementData.length > 1000,MAT 会报field elementData not accessible - 两者都支持
GROUP BY,但 MAT 要求SELECT列必须出现在GROUP BY中,jhat则宽松得多
实际排查时,真正难的不是写出某条 OQL,而是判断该对象是否“本该被回收却还在”——这需要你清楚业务逻辑里的生命周期边界,比如一个订单对象在支付完成后应被移出缓存、清空关联监听器。OQL 只负责呈现“它还在”,剩下的归因得靠引用链追溯。

















