From c1b8cda63e3b3c2ed3a75105141b559a45b2c7a2 Mon Sep 17 00:00:00 2001 From: liusiyang Date: Tue, 14 Jul 2026 15:25:42 +0800 Subject: [PATCH] =?UTF-8?q?update=20=E6=89=B9=E9=87=8F=E8=B7=91=E5=90=8C?= =?UTF-8?q?=E6=AD=A5=E6=89=A7=E8=A1=8C=EF=BC=8C=E9=81=BF=E5=85=8D=E5=86=85?= =?UTF-8?q?=E5=AD=98=E6=BA=A2=E5=87=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- example/MemMonitor.h | 50 ++++++++++++++++++ example/deal.cpp | 107 ++++++++++++++++++++++++++++++++++++++- example/deal.h | 2 + example/test_example.cpp | 8 +-- 4 files changed, 162 insertions(+), 5 deletions(-) create mode 100644 example/MemMonitor.h diff --git a/example/MemMonitor.h b/example/MemMonitor.h new file mode 100644 index 0000000..2128928 --- /dev/null +++ b/example/MemMonitor.h @@ -0,0 +1,50 @@ +#ifndef _MEM_MONITOR_H_ +#define _MEM_MONITOR_H_ + +#include +#include +#include +#include +#include + +// 获取当前进程 RSS (物理内存) 使用量,单位 MB +static inline long getRSS_KB() +{ + long rss = 0; + FILE *fp = fopen("/proc/self/status", "r"); + if (!fp) return -1; + + char line[256]; + while (fgets(line, sizeof(line), fp)) + { + if (strncmp(line, "VmRSS:", 6) == 0) + { + // 格式: "VmRSS: 12345 kB" + const char *p = line + 6; + while (*p == ' ' || *p == '\t') p++; + rss = atol(p); + break; + } + } + fclose(fp); + return rss; +} + +// 获取当前进程内存使用,打印格式化日志 +static inline void printMemUsage(const char *tag, const char *extra) +{ + long rss = getRSS_KB(); + struct rusage usage; + getrusage(RUSAGE_SELF, &usage); + printf("[MEM] %-30s | VmRSS: %6ld MB | maxRSS: %6ld MB | %s\n", + tag, rss / 1024, usage.ru_maxrss / 1024, extra ? extra : ""); +} + +// 获取产品检测 pipeline 队列深度信息快照 +#define MEM_LOG(tag, fmt, ...) \ + do { \ + long _rss = getRSS_KB(); \ + printf("[MEM] %-30s | VmRSS: %6ld MB | " fmt "\n", tag, _rss / 1024, ##__VA_ARGS__); \ + } while(0) + +#endif // _MEM_MONITOR_H_ diff --git a/example/deal.cpp b/example/deal.cpp index f8265bd..688d569 100644 --- a/example/deal.cpp +++ b/example/deal.cpp @@ -3,6 +3,7 @@ #include #include #include +#include "MemMonitor.h" #include #include #include "CheckUtil.hpp" @@ -856,6 +857,10 @@ void deal::ResultThread(int id) writeLog(strlog, m_DetResult.strlist); mutex_DetResult_.unlock(); } + + // ✅ 递增已保存结果计数,并通知等待线程,立刻唤醒检查 + m_nProductSavedResultCount.fetch_add(1); + m_productResultCV.notify_all(); } usleep(5 * 1000); @@ -1341,11 +1346,105 @@ int deal::CheckFileImg() products[i].print("产品" + std::to_string(i + 1)); } // getchar(); + printMemUsage("CheckFileImg-开始处理", ""); for (size_t i = 0; i < products.size(); i++) { - + char buf[128]; + snprintf(buf, sizeof(buf), "产品[%zu/%zu] %s 处理前", i+1, products.size(), products[i].product_id.c_str()); + printMemUsage(buf, ""); + CheckProduct(products[i]); // 处理单个产品 + + // ✅ 等待当前产品的所有检测结果保存完成,再处理下一个产品 + // 使用条件变量:ResultThread 每保存完一个结果就 notify_all,立刻唤醒检查 + printf("\n[同步] 等待产品 %s 检测结果保存完成...\n", products[i].product_id.c_str()); + { + std::unique_lock lock(mutex_Result_list); + int waitCount = 0; + while (true) + { + bool done = m_productResultCV.wait_for(lock, std::chrono::milliseconds(5000), [this]() { + return m_nProductSavedResultCount.load() >= m_nProductSuccessCount.load() + && m_Result_list.empty(); + }); + if (done) break; + waitCount++; + printf("[同步] 等待中... 已保存: %d/%d (成功:%d 失败:%d), 结果队列: %s\n", + m_nProductSavedResultCount.load(), + m_nProductSuccessCount.load() + m_nProductFailCount.load(), + m_nProductSuccessCount.load(), m_nProductFailCount.load(), + m_Result_list.empty() ? "空" : "非空"); + } + } + printf("[同步] 产品 %s 所有结果已保存完成 (saved=%d, success=%d)\n", + products[i].product_id.c_str(), + m_nProductSavedResultCount.load(), + m_nProductSuccessCount.load()); + + // ✅ 释放资源:清理图像数据,释放内存 + { + // 清理图像信息列表(已在 CheckProduct 开头清理过,这里做双重保障) + for (auto &info : m_ImageInfoList) + { + if (!info.img.empty()) + { + info.img.release(); + } + } + m_ImageInfoList.clear(); + std::vector().swap(m_ImageInfoList); // 强制释放 vector 内存 + } + + snprintf(buf, sizeof(buf), "产品[%zu/%zu] %s 资源释放后", i+1, products.size(), products[i].product_id.c_str()); + printMemUsage(buf, ""); + } + // ✅ 修复:所有产品处理完成后,通知后台线程退出 + printf("\n>>> 所有产品处理完成,正在停止后台线程...\n"); + + // 1. 通知产品读图线程退出 + m_bProductReadExit = true; + m_productTaskCV.notify_all(); + m_checkNotifyCV.notify_all(); + + // 2. 通知结果处理线程退出 + m_bExit = true; + cv.notify_all(); + + // 3. 等待产品读图线程结束 + for (auto &thread : m_productReadThreads) + { + if (thread && thread->joinable()) + { + thread->join(); + } + } + m_productReadThreads.clear(); + + // 4. 等待结果处理线程结束 + for (auto &thread : ptr_ResultthreadList) + { + if (thread && thread->joinable()) + { + thread->join(); + } + } + ptr_ResultthreadList.clear(); + + // 5. 等待 GetResult 线程结束 + if (ptr_GetResultthread && ptr_GetResultthread->joinable()) + { + ptr_GetResultthread->join(); } + ptr_GetResultthread.reset(); + + // 6. 等待 DealImg 线程结束(如果存在) + if (ptr_DealImgthread && ptr_DealImgthread->joinable()) + { + ptr_DealImgthread->join(); + } + ptr_DealImgthread.reset(); + + printf(">>> 所有后台线程已停止,程序退出.\n"); printf("\n"); // TODO: 后续实现具体功能 @@ -1383,9 +1482,15 @@ int deal::CheckProduct(const LoadProductImages &product) m_nProductPendingTasks = 0; m_nProductSuccessCount = 0; m_nProductFailCount = 0; + m_nProductSavedResultCount = 0; // 重置已保存结果计数 m_ProductFailedList.clear(); m_nCheckNotifiedCount = 0; + // ✅ 修复内存泄漏:清理上一个产品累积的原始图像数据(cv::Mat) + // 注意:m_DetResult 是统计结果(轻量字符串/数字),不清除,跨产品累积 + m_ImageInfoList.clear(); + m_productIdList.clear(); + // 3. 打印产品信息 printf("\n"); printf("╔══════════════════════════════════════════════════════════\n"); diff --git a/example/deal.h b/example/deal.h index 11f22b7..b4fe27b 100644 --- a/example/deal.h +++ b/example/deal.h @@ -799,6 +799,8 @@ public: std::mutex m_checkNotifyMutex; // 通知队列锁 std::condition_variable m_checkNotifyCV; // 通知条件变量 std::atomic m_nCheckNotifiedCount{0}; // 已通知数量 + std::atomic m_nProductSavedResultCount{0}; // 已保存结果数量(用于产品间同步等待) + std::condition_variable m_productResultCV; // 产品结果保存通知CV(每次save后notify) std::set m_productIdList; // 产品ID列表 }; diff --git a/example/test_example.cpp b/example/test_example.cpp index 74e6828..b11a05c 100644 --- a/example/test_example.cpp +++ b/example/test_example.cpp @@ -245,10 +245,10 @@ int main(int argc, char *argv[]) signal(SIGINT, handler); test.start(); - while (true) - { - usleep(10 * 1000); - } + // while (true) + // { + // usleep(10 * 1000); + // } return 0; }