ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

screenpipe 内存泄漏狩猎指南:24/7 压力循环压测与诊断工具链深度解析

screenpipe 内存泄漏狩猎指南:24/7 压力循环压测与诊断工具链深度解析 screenpipe 内存泄漏狩猎指南24/7 压力循环压测与诊断工具链深度解析【免费下载链接】screenpipeYC (S26) | Open Computer History | Record your screen continuously locally and provide context to your agents (Claude, Codex, Openclaw, Hermes, Runner...)项目地址: https://gitcode.com/GitHub_Trending/sc/screenpipe导读本文围绕 scripts/memory-leak/README.md 展开系统讲解 screenpipe 项目为根治连续运行一周后进程内存涨到 20 GB这类长驻内存泄漏问题而构建的黑盒压力测试工具链。你将掌握leak_hunt.py的采样与场景轮转原理、leak_probe.py的端点增量探测法、screenpipe-db中被忽略#[ignore]的 DB 层压力测试以及完整的命令参数、阈值判定与诊断产物解读方法可直接用于自建桌面/服务型应用的长期内存压测。一、为什么要为长驻进程做 24/7 内存压测screenpipe 是一个持续在本地录制屏幕、音频与无障碍事件并提供给 AI Agent 上下文的桌面应用。这类进程有一个共同的顽疾单次运行内无法暴露、但连续运行数小时到数天后必然出现的渐进式内存增长——常见诱因包括 FTS 全文搜索缓存未释放、WebSocket 连接不关闭、base64 响应缓冲滞留、数据库读游标泄漏等。这类问题在短时单测里几乎不可能复现只有长时间 高并发 API 压力才能把它逼出来。为此screenpipe 在 scripts/memory-leak/ 下维护了一套完整的内存泄漏狩猎工具链其核心设计哲学在 leak_hunt.py 的模块注释中写得很明确The harness is intentionally black-box: it keeps pressure on the local screenpipe API while sampling the OS process RSS. This catches leaks that only show up in the real desktop/server process after hours or days.即刻意采用黑盒方式不侵入被测进程内部而是持续对本地 screenpipe API 施压同时从操作系统层面采样进程 RSS。这正是针对只有真实桌面/服务进程运行数小时乃至数天后才出现的那类泄漏而设计的。二、整体架构采样器 场景轮转 双线程leak_hunt.py在run前台模式下同时做两件事对应两条并行的工作线采样线sampler thread每 30 秒--sample-interval-sec默认 30.0采样一次screenpipe-app、screenpipe、screenpipe-engine三者中内存占用最大的进程树的 RSS/CPU/句柄数/线程数/fd 数并滚动写入samples.jsonl与samples.csv。实现见 leak_hunt.py 的 sampler_loop。压力线主线程不断轮转 8 类压力场景每个场景持续--scenario-duration-sec默认 180 秒后切换到下一个循环往复。场景实现见 leak_hunt.py 的场景编排。默认情况下采样间隔为 30 秒进程名匹配集合为(screenpipe-app, screenpipe, screenpipe-engine)API 基址为http://127.0.0.1:3030默认常量定义。若本地 API 启用了认证可通过SCREENPIPE_API_KEY环境变量或--api-key参数传入请求会携带Authorization: Bearer key头。所有诊断产物只写入~/.screenpipe/diagnostics/memory-leak目录不会污染被测进程的工作目录python3 scripts/memory-leak/leak_hunt.py start python3 scripts/memory-leak/leak_hunt.py status --analyze python3 scripts/memory-leak/leak_hunt.py stop python3 scripts/memory-leak/leak_hunt.py run --duration-sec 900 --scenario-duration-sec 60 --concurrency 8四个子命令的分工如下子命令作用关键参数run前台运行压力循环--duration-sec控制时长默认 3600 秒--forever无限运行--duration-sec、--foreverstart以后台守护进程方式启动run --foreverPID 写入leak-hunt.pid全部公共参数status打印守护进程运行状态与当前 screenpipe 进程树信息--analyze附加分析--analyze、--since-hoursstop向守护进程发SIGTERM10 秒未退出则升级为SIGKILL--out-dirstart的实现细节值得注意start_daemon它会把完整的run --forever子进程以start_new_sessionTrue方式脱离终端stdout/stderr 重定向到daemon.log并把子进程 PID 写入leak-hunt.pid如果检测到已有存活守护进程则直接退出并提示。stop则读取 PID 文件先SIGTERM优雅停止超时 10 秒后SIGKILL兜底。三、压力场景全景9 类 API 攻击面run模式的场景轮转队列默认包含 8 个场景场景列表开启--allow-audio-toggle后追加第 9 个。每个场景由fanout函数用ThreadPoolExecutor以固定并发度持续轰炸并逐次记录成功/失败计数fanout 实现。3.1 健康轮询health_poll随机请求 17 个轻量状态端点端点清单/health、/vision/status、/vision/metrics、/audio/metrics、/audio/device/status、/audio/list、/meetings/status、/capture/hd、/data/storage-preview、/data/device-storage、/sync/status、/archive/status、/retention/status、/vault/status、/browser/status、/tags/autocomplete、/speakers/unnamed。用于制造持续的短请求流量暴露连接/上下文对象泄漏。3.2 搜索扇出search_fanout对/search端点做高基数参数组合轰炸build_search_fanout_params关键词screenpipe、meeting、github、slack、customer、error、memory、audio、todo、pricingcontent_typeall/ocr/audio/input/accessibility/memorylimit默认模式下取[10, 25, 50, 100, 250]开启帧图片时改为[5, 10, 20]offset[0, 10, 50, 100, 250]max_content_length[256, 1024, 4096]focused随机None/true/false。这组参数刻意覆盖大返回体 深分页 长文本截断的组合专门检验 FTS 搜索路径的内存回收。3.3 时间线流式推送timeline_stream通过真实的 WebSocket 协议连接/stream/frames随机选取 1/6/24/72/168 小时时间窗、ascending/descending排序、limit取[100, 500, 2000, 10000]每个连接保持 1~5 秒后断开实现。注意这里的并发被钳制在max(1, min(concurrency, 4))因为长连接流式场景并发过高会失真。值得一提脚本没有依赖第三方 WS 库而是手写了完整的 RFC 6455 客户端——包括Sec-WebSocket-Key握手、掩码帧构造ws_text_frame、短/长帧长度编码见 leak_hunt.py。这保证了它不需要任何 Python 依赖即可运行纯标准库。3.4 帧元数据行走frame_walk先通过/searchcontent_typeocr, limit100发现一批真实存在的frame_id递归遍历响应 JSON 收集frame_id字段discover_frame_ids随后随机对/frames/{id}/metadata、/frames/{id}/text、/frames/{id}/context发起读取开启帧图片时追加裸/frames/{id}图像端点并发上限 8。3.5 会议行走meeting_walk随机在list/status/query/transcript/detail五种操作间切换实现列表分页、状态查询、关键词过滤、单会议详情与全文转写读取并发上限 8。重点考察转写分段读路径。3.6 记忆/工件列表memory_artifact_lists轮询/memories含分页 offset 0/100、/memories/tags、/artifacts、/tags/autocomplete、/activity-summary端点清单。3.7 音频只读audio_readonly只读轰炸/audio/list、/audio/device/status、/audio/metrics、/audio/reconciliation/backlog并发上限 4实现。3.8 WebSocket 抖动websocket_churn对/ws/health、/ws/metrics、/ws/meeting-status、/ws/events反复建立/保持/断开 WebSocket 连接每个连接持有 1~5 秒并发上限 16实现。这是检验连接未关闭/订阅未注销类泄漏的经典手段。3.9 音频启停切换audio_toggle可选仅当传入--allow-audio-toggle时启用循环POST /audio/stop→ 等待 2 秒 →POST /audio/start→ 等待 10 秒实现。它会真实干扰正常录音因此默认关闭。四、采样与泄漏判定RSS 阈值 时均斜率双闸门4.1 进程树聚合采样由于 screenpipe 是典型的多进程应用screenpipe-app壳进程会派生screenpipe-engine、bun、mcp-helper等子进程简单采样单一 PID 会严重漏计。leak_hunt.py实现了递归进程树聚合以匹配进程为根沿 PPID 关系收集全部后代累计得到tree_rss_kb、tree_private_kb、tree_vsz_kb、tree_pcpu、tree_handle_count、tree_thread_count与descendant_countaggregate_process_tree若存在多个候选根选取整树 RSS 最大者作为采样对象find_screenpipe_process。也可用--pid指定精确的根 PID。进程数据来源分平台Linux/macOS 用ps -axo pid,ppid,rss,vsz,pcpu,commWindows 用 PowerShell 的Get-ProcessGet-CimInstance Win32_Processprocess_rowsfd 数在 Linux 下直接读/proc/{pid}/fd其他平台回退到lsof -nP -p pid。4.2 增长斜率一小时内线性回归growth_mb_per_hour对最近 1 小时窗口内的(时间, RSS)样本做最小二乘线性回归取斜率即为每小时内存增长速率growth_mb_per_hour。窗口内样本不足 3 个时返回None。4.3 双阈值与自动取证快照当满足以下任一条件时触发取证sampler_loop 判定逻辑闸门默认值触发原因标记进程树 RSS 绝对值8 GB--rss-threshold-mb默认 8192.0rss_over_8192mb一小时增长斜率512 MB/h--growth-threshold-mb-per-hour默认 512.0growth_over_512mb_per_hour触发后受--snapshot-cooldown-sec默认 3600 秒冷却限制会捕获一份快照到run-dir/snapshots/时间戳-原因-pidpid/capture_snapshotmacOS工具可用时vmmap -summary内存区域摘要、sample pid 2020 秒采样堆栈、lsof -nP -p pid打开文件清单、ps -M -p pid线程列表WindowsGet-Process -Id pid | Format-List *与Get-CimInstance Win32_Process进程树 JSON每个快照附带snapshot.json元数据时间戳、PID、触发原因、产物路径。这些产物对事后分析内存在哪个子系统里涨至关重要vmmap -summary能定位到MALLOC_SMALL、IOAccelerator图形等具体区域sample则给出热点堆栈。五、诊断产物与 status/analyze 解读每次run会话在~/.screenpipe/diagnostics/memory-leak/下创建一个以时间戳命名的运行目录内含文件内容config.json本次运行全部参数快照base_url、时长、并发、阈值、进程名、PID 等samples.jsonl每 30 秒一行的全字段采样JSON Lines含 scenario、rss_mb、growth_mb_per_hour、snapshot_reason 等samples.csv与 jsonl 同源的 CSV 版便于表格软件/脚本分析summary.json各场景 ok/err 计数汇总snapshots/触发阈值后的取证快照latest指向最近一次运行目录的符号链接analyze实现汇总--since-hours默认 24 小时内的样本输出样本数、首/末/最大 RSS、总增长量与MB/h斜率、按场景统计的 RSS min/max/样本数以及最近 10 次快照路径。其退出码有明确语义0未越过任何泄漏阈值status: no leak threshold crossed1未找到样本2判定为疑似泄漏status: suspect leak。这使status --analyze可以无缝接入 CI 或告警脚本。status还会额外打印守护进程存活状态与当前 screenpipe 进程树信息RSS、私有内存、VSZ、后代进程数。六、可选重压模式帧图片与音频启停的设计权衡默认压测刻意不包含两类高成本操作README 明确说明原因帧图片读取与音频启停更重且可能干扰正常录制。需要聚焦复现时才显式开启python3 scripts/memory-leak/leak_hunt.py start --include-frame-images python3 scripts/memory-leak/leak_hunt.py start --allow-audio-toggle--include-frame-images背后的权衡在 search_fanout 场景注释 中写得很直白内联帧图片会让服务端触发 ffmpeg 转码并在内存中滞留大块 base64 响应缓冲。因此开启后代码强制把该场景并发降为 1limit上限缩到 20且仅随机部分请求携带图片——确保压测工具本身不会成为它试图测量的那个内存压力源。这个测量者不能污染被测对象的原则是整套工具设计上最值得借鉴的地方。七、源码级守卫测试防止压测器自身退化scripts/memory-leak/test_leak_hunt.py 用unittest锁定了上述两个关键行为test_default_search_pressure_never_includes_frames连续 500 次生成搜索参数断言默认模式下include_frames恒为falsetest_opt_in_frame_pressure_uses_small_limits开启帧图片时凡是携带帧的请求limit必须 20ProcessTreeAccountingTests系列验证递归后代统计含 3 层嵌套子树、多候选根时按整树内存选根、--pid精确指定子树三种行为保证采样口径不会随重构漂移。八、DB 层压力测试内存压力测试的 Rust 侧补充黑盒 API 压测之外crates/screenpipe-db/tests/memory_pressure_test.rs 提供了一组被忽略#[ignore]的 Rust 压力测试在库层直接复现最易分配内存的操作FTS/搜索、时间线帧 join、会议转写读取以及并发写读抖动。它们默认被#[ignore]标注保证常规测试套件保持快速需要时显式运行cargo test -p screenpipe-db --test memory_pressure_test -- --ignored --nocapture测试由env_usize辅助函数驱动全部规模参数可通过环境变量调整默认值定义环境变量默认值语义SCREENPIPE_PRESSURE_FRAMES6000预置 OCR 帧数SCREENPIPE_PRESSURE_AUDIO1000预置音频转写段数SCREENPIPE_PRESSURE_UI4000预置 UI 事件数SCREENPIPE_PRESSURE_MEETINGS60预置会议数每个含 20 条转写段SCREENPIPE_PRESSURE_ROUNDS40读压力轮数SCREENPIPE_PRESSURE_MAX_RSS_GROWTH_MB1024RSS 增长断言上限SCREENPIPE_PRESSURE_CHURN_SECONDS60写读抖动持续秒数SCREENPIPE_PRESSURE_READERS4并发读者数SCREENPIPE_PRESSURE_WRITER_SLEEP_MS0写者每次插入后的睡眠毫秒数两个用例各有侧重repeated_search_timeline_meeting_reads_do_not_grow_unbounded实现先通过seed_mixed_corpus灌入混合语料多窗口 OCR 帧、音频转写、UI 事件、会议及转写段再循环执行读压力轮——对 6 种ContentType全量搜索、拉取视频块、读取前 100 帧的 metadata/text/accessibility、读取会议转写测试通过ps -o rssWindows 为Get-Process自测 RSS断言峰值增长不超过SCREENPIPE_PRESSURE_MAX_RSS_GROWTH_MB。concurrent_write_read_churn_stays_bounded实现一个写者协程持续批量插入 OCR 帧与 UI 事件可选WRITER_SLEEP_MS节流多个读者协程同时跑读压力轮持续CHURN_SECONDS后断言 RSS 增长有界——模拟真实桌面场景中一边录制写入、一边查询的并发形态。README 还给出了三组针对性变体方便聚焦特定怀疑路径# 只做读/搜索/时间线/会议压力缩小数据规模 SCREENPIPE_PRESSURE_FRAMES1000 \ SCREENPIPE_PRESSURE_AUDIO200 \ SCREENPIPE_PRESSURE_UI1000 \ SCREENPIPE_PRESSURE_MEETINGS10 \ SCREENPIPE_PRESSURE_ROUNDS8 \ cargo test -p screenpipe-db --test memory_pressure_test repeated_search_timeline_meeting_reads_do_not_grow_unbounded -- --ignored --nocapture # 纯写抖动读者为 0写者睡眠 1ms SCREENPIPE_PRESSURE_CHURN_SECONDS10 \ SCREENPIPE_PRESSURE_READERS0 \ SCREENPIPE_PRESSURE_WRITER_SLEEP_MS1 \ cargo test -p screenpipe-db --test memory_pressure_test concurrent_write_read_churn_stays_bounded -- --ignored --nocapture # 混合写读抖动4 读者 1ms 写者节流 SCREENPIPE_PRESSURE_CHURN_SECONDS10 \ SCREENPIPE_PRESSURE_READERS4 \ SCREENPIPE_PRESSURE_WRITER_SLEEP_MS1 \ cargo test -p screenpipe-db --test memory_pressure_test concurrent_write_read_churn_stays_bounded -- --ignored --nocapture这三条命令分别对应读路径排查写路径排查读写并发排查三种场景是缩小泄漏根因范围的高效手段。九、进阶工具leak_probe.py 端点增量探测当 24/7 压测确认确实在涨之后下一步是定位是哪个端点族在涨。scripts/memory-leak/leak_probe.py 与leak_hunt.py刻意互补模块注释一次只跑一个端点族health / meetings / search_no_frames / search_with_frames / memory_lists / timeline_past_1h / timeline_past_7d / timeline_live_today 等 12 个阶段而不是混合轮转使用真实/stream/framesWebSocket 协议含 SHA-1 accept key 校验见 ws_connect每个阶段前后各拍一次快照记录vmmap 内存桶增量TRACKED_VMMAP_BUCKETS包括IOAccelerator (graphics)、IOSurface、MALLOC_SMALL、MALLOC_LARGE、WebKit Malloc、DefaultMallocZone等输出Physical footprint与各桶前后差值绝不写入线上数据库、绝不重启 screenpipe纯只读。基本用法python3 scripts/memory-leak/leak_probe.py --phases search_ocr_no_frames,search_with_frames,timeline_past_7d \ --phase-seconds 25 --cooldown-seconds 8 --concurrency 2主要参数--base-url默认http://127.0.0.1:3030、--pid默认自动探测screenpipe-app进程、--phase-seconds默认 25、--cooldown-seconds默认 8留给 GC 稳定期、--concurrency默认 2、--phases逗号分隔阶段名。产物为out-dir/results.json、summary.csv与各阶段前后vmmap-phase-before/after.txt。每阶段终端会打印rss 增量 / fd 增量 / ops / errors / 读取字节数及变化最大的 4 个 vmmap 桶——例如某阶段MALLOC_LARGE 42.0MB就把怀疑范围从全局泄漏缩小到大块分配路径。十、参数速查表与推荐实战流程10.1 公共参数速查run/start均支持参数默认值说明--base-urlhttp://127.0.0.1:3030本地 screenpipe API 基址--out-dir~/.screenpipe/diagnostics/memory-leak诊断输出目录--process-namescreenpipe-app、screenpipe、screenpipe-engine可重复指定追加匹配名--pid无精确指定跟踪的根 PID含后代--api-key无或SCREENPIPE_API_KEY携带 Bearer 认证头--sample-interval-sec30.0采样间隔--scenario-duration-sec180.0每个场景持续时长--concurrency8场景并发度各场景内部还会二次钳制--rss-threshold-mb8192.0RSS 绝对阈值--growth-threshold-mb-per-hour512.0小时增长斜率阈值--snapshot-cooldown-sec3600.0快照最小间隔--request-timeout-sec30.0单个请求超时--include-frame-images关闭开启帧图片重压并发降为 1、limit≤20--allow-audio-toggle关闭开启音频启停切换会干扰录音--no-snapshots关闭关闭阈值自动取证10.2 推荐实战流程前台冒烟先用run --duration-sec 900短跑 15 分钟确认 screenpipe 正在运行、API 可达、场景无大量报错24/7 常驻start启动守护进程部署成开机任务或服务期间用status观察守护进程与进程树状态定期判读status --analyze检查斜率斜率持续高于 512 MB/h 或 RSS 触及 8 GB 时进入snapshots/阅读vmmap-summary.txt与sample.txt定位增长区域与热点栈端点定位用leak_probe.py对嫌疑端点族做分相增量探测结合 vmmap 桶差值缩小范围库层复现用第八节的memory_pressure_test定向变体在screenpipe-db层复现并验证修复跑通repeated_search_timeline_meeting_reads_do_not_grow_unbounded与concurrent_write_read_churn_stays_bounded即回归通过。十一、适用前提与平台说明压测对象是正在运行的本地 screenpipe 实例桌面版或screenpipe-engine服务默认 API 端口3030使用前请确认进程与端口已就绪进程采样在 Linux/macOS 依赖psfd 数 Linux 走/procmacOS 回退lsofWindows 依赖 PowerShell 的Get-Process/Get-CimInstancevmmap、sample等取证工具仅在 macOS 可用代码按平台条件执行Windows 下取证使用 PowerShell 命令时间线流式场景的 WebSocket 连接仅支持http://基址https下该场景直接返回失败文章中的阈值8 GB、512 MB/h、默认数据规模6000 帧、40 轮等均为仓库当前代码的默认值实际压测时应结合被测机器内存容量调整工具链全部基于 Python 标准库urllib、socket、concurrent.futures等无需额外 pip 依赖即可运行。十二、小结整套 memory-leak 工具链给出了一个可复制的长驻进程内存泄漏治理闭环黑盒 24/7 压测leak_hunt.py→ 阈值触发取证vmmap/sample/lsof→ 端点增量定位leak_probe.py→ 库层确定性复现memory_pressure_test.rs→ 修复后回归。其中测量者不得污染被测对象帧图片默认关闭且并发受限、进程树聚合采样不遗漏子进程内存、双闸门判定绝对阈值 斜率这三个设计点对任何需要长期守护内存健康的桌面/服务型项目都具有直接的移植价值。相关实现均可直接在 scripts/memory-leak/、crates/screenpipe-db/tests/memory_pressure_test.rs 中继续深入阅读。【免费下载链接】screenpipeYC (S26) | Open Computer History | Record your screen continuously locally and provide context to your agents (Claude, Codex, Openclaw, Hermes, Runner...)项目地址: https://gitcode.com/GitHub_Trending/sc/screenpipe创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表