
本文介绍一种基于 Map 的结构化方法,用于严格按行序(即相同索引位置)比对两次进程内存映射输出中各段地址是否发生变化,解决传统 HashMap 键值匹配无法保留顺序与重复文件名导致冲突的问题。
本文介绍一种基于 `map
在 Linux /proc/[pid]/maps 类输出中,同一共享库(如 /lib/libm-2.31.so)可能被映射为多个内存段(如 r-xp、---p、r--p、rw-p),且每次进程启动时各段起始地址可能动态变化。若仅用 Map
正确做法是:将每行视为一个独立映射单元,按原始顺序编号,并构造唯一键(如 /lib/libm-2.31.so#3),再将多次输出的对应地址存入 List
✅ 推荐实现方案
使用 LinkedHashMap
import java.util.*;
import java.util.Scanner;
public static Map<string list>> getMemoryAddressWithFileName(String[] responses) {
Map<string list>> map = new LinkedHashMap();
for (String response : responses) {
Scanner s = new Scanner(response);
int keyIndex = 1;
while (s.hasNextLine()) {
String line = s.nextLine().trim();
if (line.isEmpty()) continue; // 跳过空行(如开头的 "
")
// 按首个连续空白分隔:地址 + 其余字段;再提取文件路径(最后一个非空字段)
String[] parts = line.split("\s+", 6); // 限定分割数,避免路径内空格干扰
if (parts.length new ArrayList()).add(address);
}
s.close();
}
return map;
}</string></string>
? 使用示例与结果验证
public static void main(String[] args) {
String output1 = "b3e74000-b3ec5000 r-xp 00000000 fb:00 1653 /lib/libm-2.31.so
" +
"b3ec5000-b3ed4000 ---p 00051000 fb:00 1653 /lib/libm-2.31.so
" +
"b3ee7000-b3ee8000 r--p 00050000 fb:00 1653 /lib/libm-2.31.so
" +
"b3ed5000-b3ed6000 rw-p 00051000 fb:00 1653 /lib/libm-2.31.so";
String output2 = "
" +
"b3e74000-b3ec5000 r-xp 00000000 fb:00 1653 /lib/libm-2.31.so
" +
"b3ed8000-b3ee7000 ---p 00051000 fb:00 1653 /lib/libm-2.31.so
" +
"b3ee7000-b3ee8000 r--p 00050000 fb:00 1653 /lib/libm-2.31.so
" +
"b3ee8000-b3ee9000 rw-p 00051000 fb:00 1653 /lib/libm-2.31.so";
Map<string list>> resultMap = getMemoryAddressWithFileName(new String[]{output1, output2});
for (Map.Entry<string list>> entry : resultMap.entrySet()) {
List<string> addresses = entry.getValue();
if (addresses.size() == 2) {
String addr1 = addresses.get(0);
String addr2 = addresses.get(1);
boolean unchanged = addr1.equals(addr2);
System.out.printf("✅ %s → %s vs %s → %s%n",
entry.getKey(), addr1, addr2, unchanged ? "UNCHANGED" : "CHANGED");
}
}
}</string></string></string>
输出结果:
✅ /lib/libm-2.31.so#1 → b3e74000-b3ec5000 vs b3e74000-b3ec5000 → UNCHANGED ✅ /lib/libm-2.31.so#2 → b3ec5000-b3ed4000 vs b3ed8000-b3ee7000 → CHANGED ✅ /lib/libm-2.31.so#3 → b3ee7000-b3ee8000 vs b3ee7000-b3ee8000 → UNCHANGED ✅ /lib/libm-2.31.so#4 → b3ed5000-b3ed6000 vs b3ee8000-b3ee9000 → CHANGED
⚠️ 注意事项
- 顺序即语义:/proc/[pid]/maps 的行序反映内存布局逻辑(如代码段、数据段、BSS 等),必须严格按索引比对,不可依赖文件名聚合。
- 空行与格式鲁棒性:示例中 output2 开头含 ,需 trim() 或显式跳过空行,避免解析异常。
- 路径提取可靠性:使用 split("\s+", 6) 并取第 6 个元素(索引 5),比正则 (?=/) 更稳定,规避路径含空格等边界情况。
- 扩展性考虑:该结构天然支持 N 轮比对(只需传入 String[]),便于集成到自动化内存稳定性测试流程中。
通过此方案,你不仅能精准识别“哪一段地址未变”,还能明确指出“第几段发生了偏移”,真正实现面向生产环境的可审计、可追溯的内存映射一致性验证。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











