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:
1 parent
202caaf66b
commit
68ce46a5d8
19 files changed
+368
-19
No files matched your search
@@ -722,7 +722,7 @@ void autoplay_maybe(void)
|
||||
meow_log(MEOW_LOG_INFO, "autoplay: triggered, sel='%s'", buf);
|
||||
char *sel = strdup(buf);
|
||||
pthread_t t;
|
||||
if (pthread_create(&t, NULL, autoplay_worker, sel) == 0) pthread_detach(t);
|
||||
if (ncm_thread_create(&t, autoplay_worker, sel) == 0) pthread_detach(t);
|
||||
else free(sel);
|
||||
}
|
||||
|
||||
|
||||
@@ -117,6 +117,19 @@ static void save_cover_raw(const char *path, size_t len)
|
||||
|
||||
#define COVER_RETRY_MAX 8 /* 连续失败放弃次数(UI 重进页/切歌会重新提交目标) */
|
||||
|
||||
/* 内存瘦身:封面解码后按显示上限降采样驻留。网易云全尺寸封面(如 1448×1448)解码成
|
||||
* RGBA = 8MB,而应用显示只需 ≤480px(播放页黑胶方图+歌词页模糊铺底均 ≤ 屏幕 480 宽)——
|
||||
* 缩到 480×480 = 0.9MB,省 ~7MB anon(设备 RAM 仅 56MB,OOM 真机被杀,最高优先级)。
|
||||
* 若已 ≤上限(小缩略图)则原样保留。返回本函数处理后的图(可能替换/释放旧图)。 */
|
||||
#define NCM_COVER_DECODE_MAX 480
|
||||
static meow_img *cover_cap(meow_img *im)
|
||||
{
|
||||
if (!im) return NULL;
|
||||
meow_img *small = meow_img_downscale(im, NCM_COVER_DECODE_MAX);
|
||||
if (small) { meow_img_free(im); return small; } /* 已缩放:释放原始大图,换小图驻留 */
|
||||
return im; /* 本就够小:保留原图 */
|
||||
}
|
||||
|
||||
static void *cover_worker(void *arg)
|
||||
{
|
||||
(void)arg;
|
||||
@@ -168,6 +181,8 @@ static void *cover_worker(void *arg)
|
||||
}
|
||||
}
|
||||
}
|
||||
/* 内存瘦身:全尺寸封面解码后降采样到 ≤480px 驻留(省 ~7MB anon,OOM 修复)。 */
|
||||
if (img) img = cover_cap(img);
|
||||
if (!img) {
|
||||
/* 失败:指数退避重试,连续 COVER_RETRY_MAX 次放弃(不无声死等;
|
||||
* 目标保留期间 UI 每帧重请求由 cover_request 去重挡住)。 */
|
||||
@@ -218,7 +233,7 @@ void cover_request(const char *url)
|
||||
pthread_mutex_unlock(&g_cm);
|
||||
if (!g_thr_on) {
|
||||
g_thr_on = 1;
|
||||
if (pthread_create(&g_thr, NULL, cover_worker, NULL) == 0)
|
||||
if (ncm_thread_create(&g_thr, cover_worker, NULL) == 0)
|
||||
pthread_detach(g_thr);
|
||||
else
|
||||
g_thr_on = 0;
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <pthread.h>
|
||||
#include <limits.h>
|
||||
#include "meow_ui.h"
|
||||
#include "meow_ui_view.h"
|
||||
#include "ncm.h" /* 核心库伞头(ctx/api/login/cache/...) */
|
||||
@@ -81,6 +82,21 @@
|
||||
/* active_playlist 哨兵:搜索歌单详情(复用 playlist_open 链路,读 g_st.search_pl_open) */
|
||||
#define NCM_PL_SEARCH (-2)
|
||||
|
||||
/* 线程创建:显式小栈(内存瘦身,OOM 修复)。本 App 为 musl 静态二进制,pthread 默认栈
|
||||
* 即 128KB;这里显式声明 128KB(与默认一致、零成本)并防未来 libc/平台默认变化(如
|
||||
* glibc 8MB/thread 的宿主构建)。实测网络/解码调用链栈深 ≤~30KB,128KB 充足。
|
||||
* 返回 pthread_create 结果。 */
|
||||
#define NCM_THREAD_STACK (128 * 1024)
|
||||
static inline int ncm_thread_create(pthread_t *t, void *(*fn)(void *), void *arg)
|
||||
{
|
||||
pthread_attr_t a;
|
||||
pthread_attr_init(&a);
|
||||
pthread_attr_setstacksize(&a, (size_t)NCM_THREAD_STACK);
|
||||
int r = pthread_create(t, &a, fn, arg);
|
||||
pthread_attr_destroy(&a);
|
||||
return r;
|
||||
}
|
||||
|
||||
/* ---- 播放/媒体会话状态(play 线程 ↔ UI/IPC 共享,mu 保护)---- */
|
||||
enum {
|
||||
NCM_PC_STOPPED = 0,
|
||||
|
||||
@@ -205,7 +205,7 @@ int ipc_media_start(void)
|
||||
{
|
||||
if (g_thr_on) return 0;
|
||||
g_quit = 0;
|
||||
if (pthread_create(&g_thr, NULL, ipc_thread, NULL) != 0) return -1;
|
||||
if (ncm_thread_create(&g_thr, ipc_thread, NULL) != 0) return -1;
|
||||
pthread_detach(g_thr);
|
||||
g_thr_on = 1;
|
||||
return 0;
|
||||
|
||||
@@ -369,7 +369,7 @@ static int song_download_attempt(const ncm_song_t *s, int idx, int seq, const ch
|
||||
size_t cap = (ext[0] == 'f') ? (1024u << 20) : (64u << 20);
|
||||
ss->maxb = (u.size > 0 && (uint64_t)u.size < cap) ? (size_t)u.size : cap;
|
||||
ncm_strlcpy(ss->url, u.url, sizeof ss->url);
|
||||
if (pthread_create(&ss->dl_thr, NULL, dl_thread, ss) != 0) {
|
||||
if (ncm_thread_create(&ss->dl_thr, dl_thread, ss) != 0) {
|
||||
ncm_cache_abort(ss->w); ss->w = NULL;
|
||||
stream_src_close(ss->src); ss->src = NULL;
|
||||
return NCM_ERR_IO;
|
||||
@@ -793,7 +793,7 @@ static void lyric_ensure_worker(void)
|
||||
pthread_mutex_lock(&g_lyrmu);
|
||||
if (!g_lyr_thr_on) {
|
||||
g_lyr_thr_on = 1;
|
||||
if (pthread_create(&g_lyr_thr, NULL, lyric_worker, NULL) == 0) pthread_detach(g_lyr_thr);
|
||||
if (ncm_thread_create(&g_lyr_thr, lyric_worker, NULL) == 0) pthread_detach(g_lyr_thr);
|
||||
else g_lyr_thr_on = 0;
|
||||
}
|
||||
pthread_mutex_unlock(&g_lyrmu);
|
||||
@@ -825,7 +825,7 @@ int player_manager_start(void)
|
||||
g_cache_gb = g_st.cache_limit_gb;
|
||||
pthread_mutex_init(&g_play.mu, NULL);
|
||||
meow_audio_on_preempt(on_audio_preempt, NULL); /* 被抢占 → 暂停(SDK 读线程分发) */
|
||||
if (pthread_create(&g_thr, NULL, player_thread, NULL) != 0) return -1;
|
||||
if (ncm_thread_create(&g_thr, player_thread, NULL) != 0) return -1;
|
||||
g_thr_on = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -233,7 +233,7 @@ void home_reload(void)
|
||||
g_home_loading = 1;
|
||||
}
|
||||
g_home_thr_on = 1;
|
||||
if (pthread_create(&g_home_thr, NULL, home_worker, NULL) != 0) {
|
||||
if (ncm_thread_create(&g_home_thr, home_worker, NULL) != 0) {
|
||||
g_home_thr_on = 0; g_home_loading = 0; g_load_err = NCM_ERR_IO;
|
||||
}
|
||||
home_apply();
|
||||
|
||||
@@ -176,7 +176,7 @@ int login_start(void)
|
||||
g_polling = 1;
|
||||
g_done = 0;
|
||||
g_err = 0;
|
||||
if (pthread_create(&g_thread, NULL, login_worker, NULL) != 0) {
|
||||
if (ncm_thread_create(&g_thread, login_worker, NULL) != 0) {
|
||||
g_polling = 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -306,7 +306,7 @@ static void pl_maybe_ensure(void)
|
||||
g_ens_first = 0;
|
||||
g_plloading = 1;
|
||||
g_plthr_on = 1;
|
||||
if (pthread_create(&g_plthr, NULL, playlist_worker, NULL) != 0) {
|
||||
if (ncm_thread_create(&g_plthr, playlist_worker, NULL) != 0) {
|
||||
g_plthr_on = 0; g_plloading = 0; ncm_snack("加载失败");
|
||||
}
|
||||
}
|
||||
@@ -340,7 +340,7 @@ void playlist_refresh(void)
|
||||
g_pl_stale = 0;
|
||||
g_plloading = 1;
|
||||
g_plthr_on = 1;
|
||||
if (pthread_create(&g_plthr, NULL, playlist_worker, NULL) != 0) {
|
||||
if (ncm_thread_create(&g_plthr, playlist_worker, NULL) != 0) {
|
||||
g_plthr_on = 0; g_plloading = 0; g_load_err = NCM_ERR_IO;
|
||||
}
|
||||
pl_apply(1);
|
||||
|
||||
@@ -211,7 +211,7 @@ static void sr_maybe_load_more(void)
|
||||
g_req_tab = g_tab; g_req_offset = n; g_req_replace = 0;
|
||||
/* 单飞:无 worker 才发(search_worker 尾部解锁) */
|
||||
g_thr_on = 1; g_loading = 1; g_more_err = 0;
|
||||
if (pthread_create(&g_thr, NULL, search_worker, NULL) != 0) {
|
||||
if (ncm_thread_create(&g_thr, search_worker, NULL) != 0) {
|
||||
g_thr_on = 0; g_loading = 0; g_more_err = 1;
|
||||
}
|
||||
}
|
||||
@@ -270,7 +270,7 @@ void search_submit(const char *kw)
|
||||
g_st.search_err = 0;
|
||||
g_loading = 1; g_more_err = 0;
|
||||
g_thr_on = 1;
|
||||
if (pthread_create(&g_thr, NULL, search_worker, NULL) != 0) {
|
||||
if (ncm_thread_create(&g_thr, search_worker, NULL) != 0) {
|
||||
g_thr_on = 0; g_loading = 0; g_st.search_err = NCM_ERR_IO;
|
||||
}
|
||||
sr_apply();
|
||||
@@ -290,7 +290,7 @@ static void sr_set_tab(int t)
|
||||
g_req_tab = g_tab; g_req_offset = 0; g_req_replace = 1;
|
||||
g_loading = 1; g_more_err = 0;
|
||||
g_thr_on = 1;
|
||||
if (pthread_create(&g_thr, NULL, search_worker, NULL) != 0) {
|
||||
if (ncm_thread_create(&g_thr, search_worker, NULL) != 0) {
|
||||
g_thr_on = 0; g_loading = 0;
|
||||
}
|
||||
}
|
||||
@@ -354,7 +354,7 @@ int search_on_tap(int x, int y)
|
||||
g_req_tab = g_tab; g_req_offset = 0; g_req_replace = 1;
|
||||
g_loading = 1;
|
||||
g_thr_on = 1;
|
||||
if (pthread_create(&g_thr, NULL, search_worker, NULL) != 0) {
|
||||
if (ncm_thread_create(&g_thr, search_worker, NULL) != 0) {
|
||||
g_thr_on = 0; g_loading = 0; g_st.search_err = NCM_ERR_IO;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user