You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在dump文件中按值过滤变量?VisualVM筛选ConcurrentHashMap方案

遇到这种条目太多没法手动排查的情况,确实头疼,我给你分两种场景来解决:一种是处理你手里已有的dump文件,快速定位目标条目;另一种是后续运行时的监控方案,帮你避免下次还要靠dump排查。

处理现有dump文件的方案

使用VisualVM的OQL查询

VisualVM自带的*OQL(对象查询语言)*可以帮你精准筛选出目标键对应的条目,不用手动翻找。步骤如下:

  1. 打开你的dump文件,切换到「OQL」标签页
  2. 粘贴以下查询语句并运行:
// 定位所有ConcurrentHashMap中键为"rn64832"的条目
var targetKey = "rn64832";
var results = [];

// 遍历堆中所有ConcurrentHashMap实例
heap.objects("java.util.concurrent.ConcurrentHashMap").forEach(function(map) {
  var table = map.table; // 访问ConcurrentHashMap的内部数组
  if (!table) return;
  
  // 遍历数组中的每个节点链
  for (var i = 0; i < table.length; i++) {
    var node = table[i];
    while (node) {
      var key = node.key;
      if (key && key.toString() === targetKey) {
        results.push({
          所属Map: map,
          目标键: key,
          对应值: node.value,
          节点详情: node
        });
      }
      node = node.next;
    }
  }
});

results;

运行后会返回所有包含rn64832键的条目,你可以直接查看对应的值、所属的Map实例,甚至节点的其他属性,快速定位异常。

换用Eclipse Memory Analyzer (MAT)

如果VisualVM的OQL满足不了需求,MAT是更专业的内存分析工具,查询能力更强:

  1. 导入你的dump文件到MAT
  2. 点击顶部菜单栏的「Window」→「Show View」→「Query Browser」,打开查询浏览器
  3. 选择「OQL Query」,粘贴以下语句执行:
SELECT map, entry.key, entry.value
FROM java.util.concurrent.ConcurrentHashMap map
JOIN map.table table
JOIN table[] entry
JOIN entry.key key
JOIN entry.value value
WHERE key.toString() = 'rn64832'

MAT会返回结构化的结果,你还可以右键条目查看引用链、对象详情,深入分析值异常的原因。

运行时实时检查的方案

如果后续需要监控这个键的动态变化,不用再依赖dump,可以试试这些方法:

代码层添加日志监控

如果可以修改业务代码,封装ConcurrentHashMap的操作方法,针对目标键添加日志:

private final ConcurrentHashMap<String, Object> yourMap = new ConcurrentHashMap<>();

public Object getTargetValue(String key) {
  Object value = yourMap.get(key);
  if ("rn64832".equals(key)) {
    // 打印线程信息、值内容和调用栈,方便定位操作来源
    System.out.printf("[Monitor] Thread: %s | Key: %s | Value: %s | Stack: %s%n",
        Thread.currentThread().getName(),
        key,
        value != null ? value.toString() : "null",
        Arrays.toString(Thread.currentThread().getStackTrace()));
  }
  return value;
}

public Object putTargetValue(String key, Object value) {
  Object oldValue = yourMap.put(key, value);
  if ("rn64832".equals(key)) {
    System.out.printf("[Monitor] Thread: %s | Key: %s | OldValue: %s | NewValue: %s | Stack: %s%n",
        Thread.currentThread().getName(),
        key,
        oldValue != null ? oldValue.toString() : "null",
        value != null ? value.toString() : "null",
        Arrays.toString(Thread.currentThread().getStackTrace()));
  }
  return oldValue;
}

这样运行时就能实时看到rn64832键的所有操作,包括值的变化和触发操作的调用栈。

用动态追踪工具(比如Arthas)

如果不想修改代码,Arthas是绝佳的选择——它可以无侵入地监控JVM运行时的方法调用:

  1. 下载Arthas并启动,attach到你的Java进程
  2. 执行以下命令监控put方法:
# 监控ConcurrentHashMap的put方法,仅当键为rn64832时打印参数和返回值
watch java.util.concurrent.ConcurrentHashMap put '{params, returnObj, thread.name}' -x 2 -c "params[0] == 'rn64832'"
  1. 再执行命令监控get方法:
watch java.util.concurrent.ConcurrentHashMap get '{params, returnObj, thread.name}' -x 2 -c "params[0] == 'rn64832'"

命令中的-x 2表示展开2层对象结构,-c是条件过滤,这样就能实时捕获目标键的所有操作,不用改一行代码。

自定义监控子类

如果可以控制ConcurrentHashMap的创建,可以写一个子类重写核心方法,添加监控逻辑:

public class MonitoredCHM<K, V> extends ConcurrentHashMap<K, V> {
  @Override
  public V put(K key, V value) {
    V oldValue = super.put(key, value);
    if ("rn64832".equals(key)) {
      // 这里可以记录日志、发送告警或者写入监控系统
      System.err.printf("[CHM Monitor] Put key 'rn64832': old=%s, new=%s%n", oldValue, value);
    }
    return oldValue;
  }

  @Override
  public V get(Object key) {
    V value = super.get(key);
    if ("rn64832".equals(key)) {
      System.err.printf("[CHM Monitor] Get key 'rn64832': value=%s%n", value);
    }
    return value;
  }
}

然后把原来的new ConcurrentHashMap<>()替换成new MonitoredCHM<>(),这样业务代码不用修改,就能自动监控目标键的操作。


内容的提问来源于stack exchange,提问作者Jiayi Liao

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.13 09:06:04