cpp
.\_build\_deploy\bin\example_euroc_old.exe "C:\ws\polaries\demo\SLAMConfig.json" "C:\data\hulk_#3\SLAMCalibration.json" "C:\data\hulk_#3\data\hulk_3_test_3\" "C:\data\hulk_#3\data\hulk_3_test_3\timestamp.txt"
cpp
if( i % 100 == 0){
std::cout << "Processing frame: " << i << std::endl;
std::cin.get();
}
搜索找到对应的执行程序

选中点击 attach
进入检测运行的程序界面如下
snapshoot 使能
获取当前内存中的堆管理数据,点击后获取第一次快照
回到这个程序执行界面
点击任意按键程序继续运行,这个时候开始第二次运行的 堆栈的积累

如下程序运行到 100 次之后再一次暂停,如果由内存泄漏,堆栈会有增加如下

重复上面的操作
多次 执行上面的操作循环
如上,多次操作分析对应的堆栈,给出分析结果。
怎么使用这个文件?
你提供了 三次不同时间点的 Visual Studio 内存诊断快照(Snapshot) ,我们可以用这些 View Heap 数据 来对比堆内存变化,定位内存泄漏的位置 ,并指导你如何 找到对应代码。
✅ 一、三次快照关键数据对比(从图中提取)
我们以 第5个快照(时间为 268.15s) 为例,三次运行的堆内存数据如下:
运行次数 | 时间 | 总分配次数 | 堆大小(KB) | 备注 |
---|---|---|---|---|
第1次 | 268.15s | 1,042,374 | 103,297.91 KB | 基准 |
第2次 | 268.15s | 1,042,374 | 103,297.91 KB | 相同 |
第3次 | 268.15s | 1,042,374 | 103,297.91 KB | 相同 |
📌 结论:
- 三次运行的 内存增长完全一致。
- 说明泄漏是 稳定复现的,不是随机行为。
- 你可以 稳定地调试和分析泄漏点。
✅ 二、内存增长过程(以第一次为例)
快照 | 时间 | 分配次数 | 堆大小(KB) | 每次增量(KB) |
---|---|---|---|---|
#1 | 6.83s | 40 | 21.60 KB | --- |
#2 | 31.99s | 249,598 | 56,558.35 KB | +56,536 KB |
#3 | 65.34s | 473,960 | 69,778.50 KB | +13,220 KB |
#4 | 100.33s | 701,265 | 76,144.98 KB | +6,366 KB |
#5 | 268.15s | 1,042,374 | 103,297.91 KB | +27,152 KB |
📈 趋势分析:
- 初期 爆发式分配(可能是初始化)。
- 后期 持续增长 ,无释放迹象。
- 是 典型的内存泄漏模式。
✅ 三、如何找到泄漏的代码位置?
🔍 步骤 1:在 Visual Studio 中打开 View Heap
- 在 快照 #5(268.15s) 上点击 "View Heap"。
- 会打开一个窗口,显示 所有堆上的对象类型 和 它们的大小/数量。
🔍 步骤 2:找增长最多的对象类型
在 View Heap 中,按 "Size" 或 "Count" 排序,找出:
- 哪些对象类型持续增长 (比如
std::unordered_map<MyClass>
) - 哪些对象数量每次快照都在增加
📌 重点看:
- 自定义类(比如
Landmark
,Frame
,MapPoint
) - STL 容器(比如
std::vector
,std::shared_ptr<MyClass>
)
🔍 步骤 3:查看分配调用栈(Allocation Call Stack)
在 View Heap 中:
- 选中一个 增长明显的对象类型
- 点击 "View Call Stack" 或 "Allocation Stack"
- 会显示 是哪个函数在一直分配它
📌 你之前提供的调用栈示例:
slam_core_engine.dll!UpdaterLAMdelayed_init(...)
slam_core_engine.dll!VioManager::frame_bundle_handler(...)
→ 说明每次帧处理都会调用这个函数,持续插入对象到 map 中 ,但 不清理
✅ 四、总结:你怎么找到泄漏的代码
步骤 | 操作 | 目的 |
---|---|---|
1 | 点击快照 → View Heap | 看哪些对象在增长 |
2 | 排序 by Size / Count | 找出增长最多的类型 |
3 | 选中对象 → View Call Stack | 看是哪个函数在分配 |
4 | 打开源码 → 检查是否只 insert 不 erase | 找到泄漏逻辑 |
5 | 检查 shared_ptr 是否循环引用 | 避免智能指针互相持有 |
✅ 五、总结一句话
你在 View Heap 里要找到"持续增长"的对象类型,然后看它的分配调用栈,就能定位到是哪个函数在持续分配但不释放------这就是内存泄漏的代码位置。
如果你能把你 View Heap 里的对象类型列表 贴出来(比如 std::unordered_map<unsigned int, std::shared_ptr<Landmark>>
这种),我可以帮你 精确定位是哪一行代码泄漏 ,并给出 修复建议。
下面是第二阶段对比操作流程细节:
下面给出在 Visual Studio 2022 里把两个内存快照拿出来对比 的完整路径,一步一步截图式指引,你照着点即可。
✅ 1. 确保正在调试
- 必须以 "Debug" 模式启动(F5)。
- 启动后,Diagnostic Tools 窗口会自动弹出。
若没看到:
菜单栏 → Debug → Windows → Show Diagnostic Tools
(Ctrl + Alt + F2)
✅ 2. 切到 Memory Usage 页签
- 在 Diagnostic Tools 窗口顶部 有一排小页签
CPU Usage | Memory Usage | Events
→ 点 Memory Usage
✅ 3. 找到 Snapshots 表格
- 同窗口下半区 有一个 "Snapshots" 列表(时间轴下方)。
每一行就是一次快照,列头为
Time | Allocations (Diff) | Heap Size (Diff)
✅ 4. 拍快照(如果还没拍)
- 调试过程中,随时点 "Take Snapshot" 按钮(左上角小相机图标)。
拍完后,该行会出现在 Snapshots 列表里。
✅ 5. 选中两个快照
- 按住 Ctrl → 左击两行(例如 #2 和 #5)。
两行同时高亮即可。
✅ 6. 对比快照
- 有两种方式启动对比:
- 右键 → Compare Snapshots
- 列表上方工具栏 "Compare Snapshots" 按钮(两个圆圈图标)
✅ 7. 看差异结果
- VS 会弹出 新标签页
Snapshot Diff #2 vs #5
。
里面列出 增长/减少的对象类型 ,按 Size Diff 排序即可一眼看出谁涨了几十 MB。
✅ 8. 定位代码
- 在差异表里 双击某个类型 → 打开 Allocation View。
- 再点 "View Call Stack" (或右侧小栈图标),就能看到 哪一行
operator new
一直被执行。
✅ 9. 回到源码
- 调用栈最顶层是你自己的函数,双击该行 → 直接跳到
.cpp
的对应行。
接下来你就检查是不是 只insert
/new
不erase
/delete
即可。
🔍 一张图总结(VS2022 界面)
┌─ Diagnostic Tools ─────────────────────────────┐
│ [CPU Usage] [Memory Usage] [Events] │← 2. 点 Memory Usage
│ │
│ Time轴 │
│ │ ●───●────●───●─────●──► │
│ │
│ Snapshots │
│ □ Time Allocations(Diff) Heap Size(Diff) │← 3. 快照列表
│ #1 6.83s 40 21.60 KB │
│ #2 ... +249 558 +56 536 KB │
│ #5 ... +1 042 374 +103 297 KB │← 5. Ctrl 选中两行
│ │
│ [← Take Snapshot] [Compare Snapshots] │← 6. 右键或按钮对比
└─────────────────────────────────────────────────┘
照这个流程,30 秒就能把泄漏对象、调用栈、源码行号全挖出来 。
如果你在哪个小环节没看到按钮或列表,直接截图给我,我帮你圈出来。
你现在已经走到 VS2022 的"对比快照"界面 了!
截图里能看到:
- 左上角提示:
"Compare With Baseline: Snapshot #4"
→ 说明你正在用 Snapshot #4(100.33 s)作为基准,与其他快照对比。 - 下方表格:
Object Type | Count Diff | Size Diff (Bytes)
→ 这就是 "谁涨了、涨了多少" 的差异表。
✅ 下一步:定位泄漏对象 & 代码

① 先确认对比的是哪两个快照
当前视图是把 #4 当作 baseline ,对比的是 #5(268.15 s)
(因为 #5 是最新一次,Time=268.15 s 那行高亮)。
如果你想换别的 baseline,只需:
- 在 Snapshots 列表里右键任意一行 → Set as Baseline
再点 View Diff 即可。
② 看差异表(已经在你图上)
Object Type | Count Diff | Size Diff |
---|---|---|
void |
+1,187 | +73,487 B |
这只是 系统未解析的块 (俗称"匿名分配"),还没展开 具体 C++ 类型 。
→ 需要把"未解析"展开成真实类型。
③ 取消"隐藏未解析分配"
在差异表上方有一条复选框:
☐ Hide Unresolved Allocations
→ 把它 取消勾选
立刻会出现 具体的 C++ 类名 / STL 容器名 ,例如
std::unordered_map<unsigned int,std::shared_ptr<Landmark>>
std::vector<CVHelper::Image>
等等。
④ 按 Size Diff 排序
点 Size Diff (Bytes) 列头,从大到小排 。
增长最多的类型排在第一行,它就是泄漏主角。
⑤ 看调用栈
-
双击 那一行(或右键 → View Call Stack)
→ 弹出 Allocation Stack ,里面逐层显示:slam_core_engine.dll!operator new slam_core_engine.dll!VioManager::frame_bundle_handler example_euroc_old.exe!main
-
双击最顶层你熟悉的函数 ,VS 会跳到 .cpp 源文件对应行。
✅ 一张图总结你当前该点的按钮
┌─ Diagnostic Tools ─────────────────────────────┐
│ Compare With Baseline: Snapshot #4 │← 确认 baseline
│ │
│ ☑ Hide Unresolved Allocations ←取消勾选! │
│ │
│ Object Type Count Diff Size Diff (Bytes) │
│ void +1 187 +73 487 │← 取消勾选后这里
│ ........ │ 会变成具体类名
│ │
│ [View Diff] [View Call Stack] │← 双击行或点这里
└────────────────────────────────────────────────┘
✅ 30 秒操作清单
- 取消勾选 Hide Unresolved Allocations
- 按 Size Diff 从大到小排序
- 双击增长最多的那一行
- 在弹出窗口点 View Call Stack
- 双击栈里最顶层自己的函数 → 源码行现身
做完这 5 步,泄漏代码行就摆在面前了。