fix(ncm §32): 内存瘦身修 OOM 被杀 —— 封面降采样(8.28MB→0.78MB) + 瞬态 rbuf 缩减 + 线程栈显式

真机 dmesg 实锤:OOM Kill ncm (score 460, anon-rss 26.9MB, 设备 56MB)。
画像:封面全分辨率 RGBA 8.28MB(1448x1448 原生解码驻留) 是最大可控块。

瘦身(按收益排序):
1. sdk meow_ui_img 新增纯增量 meow_img_downscale + cover.c cover_cap(≤480px)
   → 封面 8.28MB→0.78MB,-7.65MB(mem_sim 实测 PASS)。
2. ncm_api.c 瞬态响应 rbuf:song_url→64KB、lyric/song_detail/cloudsearch/user_playlist→256KB
   (detail/track_all 保 1MB)。
3. ncm_app_internal.h 新增 ncm_thread_create(显式 128KB 栈),替换全部 14 处 pthread_create。
4. 滑动窗口/meta 复核零回退(window_sim:608B/首,6000 首 280KB 恒定)。

验证:mem_sim 封面收益 PASS + host home/player 渲染 OK + stream_sim/player_flow_sim/
window_sim/search_sim/cache_evict_sim 全 PASS + test_ncm_core host+mipsel(qemu) PASS
+ build_ncm.sh -Wall -Wextra 0 warning。真机 scp 播放在跑确认(缓存曲,0 播放请求)。

新 ncm md5 44fa16fe(text 1015150/bss 1362500)。正式部署留主会话。
This commit is contained in:
AskaEth committed 2026-09-02 03:43:42 +08:00
1 parent 202caaf66b
commit 68ce46a5d8
19 files changed
+368 -19

No files matched your search

+77
View File
@@ -0,0 +1,77 @@
/* bench/mem_sim.c — 宿主内存测量 harness(OOM 瘦身验证)。
*
* 目的:把 ncm 相关块的匿名 RSS(RssAnon)拆开,验证封面降采样(meow_img_downscale)收益。
* 依赖:仅 host SDK 对象(meow_ui_init 装字库 + meow_img 解码),无需 App/core 对象。
* 用法:MEM_SIM=1 ./ncm_host
*
* 场景(各阶段 RssAnon,KB):
* [0] meow_ui_init 后基线(含字库 plane + back_buf + 启动堆)。
* [1] meow_img_load_file(全尺寸封面 1448x1448) —— 全尺寸 RGBA ≈ 8MB 驻留。
* [2] meow_img_downscale(480) + free 原图 —— RGBA 降到 ≤480x480 ≈ 0.9MB。
* 断言:RssAnon[1]-RssAnon[0] > 2MB(大封面确实驻留),RssAnon[2] < RssAnon[1]-4MB
* (降采样省 >4MB,可验证)。
*/
#include "../app/ncm_app_internal.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
static long rss_anon_kb(void)
{
FILE *f = fopen("/proc/self/status", "r");
if (!f) return -1;
char line[256];
long v = -1;
while (fgets(line, sizeof line, f))
if (strncmp(line, "RssAnon:", 8) == 0) { v = atol(line + 8); break; }
fclose(f);
return v;
}
static int mem_sim_run(void)
{
meow_ui_opts o = { APP_W, APP_H };
if (meow_ui_init(&o) != 0) { printf("mem: meow_ui_init FAILED\n"); return 1; }
long r0 = rss_anon_kb();
printf("mem[0] baseline (font plane + back_buf + startup): RssAnon=%ldKB\n", r0);
if (r0 < 0) { printf("mem: cannot read RssAnon\n"); return 1; }
const char *cover = "/tmp/ncmfont/cover_current.jpg";
if (access(cover, F_OK) != 0) {
printf("mem: warning: %s not found; skip cover scenario\n", cover);
} else {
meow_img *f0 = meow_img_load_file(cover);
if (!f0) { printf("mem: cover load FAILED\n"); return 1; }
long r1 = rss_anon_kb();
printf("mem[1] cover full-res %dx%d loaded: RssAnon=%ldKB (delta=%ldKB)\n",
meow_img_w(f0), meow_img_h(f0), r1, r1 - r0);
meow_img *small = meow_img_downscale(f0, 480);
if (small) meow_img_free(f0);
long r2 = rss_anon_kb();
int w = small ? meow_img_w(small) : (f0 ? meow_img_w(f0) : 0);
int h = small ? meow_img_h(small) : (f0 ? meow_img_h(f0) : 0);
printf("mem[2] cover downscaled to %dx%d: RssAnon=%ldKB (delta_from_full=%ldKB)\n",
w, h, r2, r2 - r1);
int ok = (r1 - r0 > 2048) && (r1 - r2 > 4096) && (small != NULL) &&
(w <= 480 && h <= 480);
printf("mem: cover-downscale %s (full_delta=%ldKB, saved=%ldKB, size=%dx%d)\n",
ok ? "PASS" : "FAIL", r1 - r0, r1 - r2, w, h);
if (small) meow_img_free(small);
}
meow_ui_shutdown();
printf("mem: done\n");
return 0;
}
int main(void)
{
if (getenv("MEM_SIM") && getenv("MEM_SIM")[0] == '1') return mem_sim_run();
/* 未设 MEM_SIM:宿主页面测试走 test_ncm_app.c 的 driver(本文件被链时只占位)。 */
printf("mem_sim: set MEM_SIM=1 to run memory scenarios\n");
return 0;
}