Skip to content

perf: Amortize GC latency - #431

Merged
hchunhui merged 1 commit into
hchunhui:masterfrom
ksqsf:gc-opt
May 2, 2026
Merged

hchunhui merged 1 commit into
hchunhui:masterfrom
ksqsf:gc-opt

Conversation

@ksqsf

@ksqsf ksqsf commented May 2, 2026

Copy link
Copy Markdown
Contributor

follow-up: #308
follow-up: #396

变更

#396 的基础上引入 step(32) 从而均摊 full gc 的延迟

现有问题

目前每次 LuaTranslation 析构都会触发一次 full gc。若 lua 中有较大 table,每次 full gc 都会扫描一遍。实测显示我这里每次 full gc 有至少 1ms 的延迟,则每增加一个 lua filter,都会增加 1ms 的延迟,有明显体感。事实上,该延迟还可能因各种因素叠加(如 lua 中状态积累导致扫描的对象数量越来越多),最终总按键延迟可能超过 10ms 乃至更多。

变更后效果

  1. 大多数按键延迟大大降低:大部分 step gc 耗时为 0,故大部分按键延迟为 0。
  2. 即使 step gc 耗时非 0,实际耗时也往往在 6ms 以下,10ms 以上的延迟极少。对用户来说感知并不明显。
  3. 内存占用较为稳定,我这里约在 40MB +- 10MB 间。但相比每次都进行 full gc 来说波动增加了。

@ksqsf ksqsf changed the title perf: Amortize gc latency perf: Amortize GC latency May 2, 2026
@hchunhui
hchunhui merged commit ec52e48 into hchunhui:master May 2, 2026
6 checks passed
@shewer

shewer commented May 2, 2026

Copy link
Copy Markdown
Contributor

請問 lua table 是在 M.func 中動態產生的臨時資料嗎,
如果是引用 lua table 自定字典 (常駐字典) 應該也無法回收,
librime-lua userdata 都是 shared_ptr ,爲何會在lua_state 中產生那麼大的資料呢?

如果把 lua->gc() 增加 參數 可以選擇
Lua::gc(int what=LUA_GCCOLLECT, int data = 0) {
lua_gc(L_, what, data);
}

LuaTranslation::LuaTranslation() 儲存 LUA_GCCOUNT (當時的使用量)
LuaTranslation::~LuaTranslation() 使用lua_gc(L, LUA_GCSTEP, 目前使用量-當時使用量)
會不會好一點

@ksqsf

ksqsf commented May 2, 2026

Copy link
Copy Markdown
Contributor Author

这里指的是module或component init时产生的大型查询表。正是因为一直无法回收,full gc反复扫描才会导致浪费时间。要解决这个问题我感觉只能是提供某种api把table转换成C++侧的数据来避免扫描了……

具体参数是我测出来的,肯定还有改进空间,不过我发现step取一个较保守的参数似乎没有什么问题。

@ksqsf
ksqsf deleted the gc-opt branch May 2, 2026 12:20
@shewer

shewer commented May 3, 2026

Copy link
Copy Markdown
Contributor

这里指的是module或component init时产生的大型查询表。正是因为一直无法回收,full gc反复扫描才会导致浪费时间。要解决这个问题我感觉只能是提供某种api把table转换成C++侧的数据来避免扫描了……

具体参数是我测出来的,肯定还有改进空间,不过我发现step取一个较保守的参数似乎没有什么问题。

luafilter module 是用 requile file(lua_gears.cc:raw_init) return table {func fini init} ,
renew luafilter 也只是從 package.loaded 中取出 module table
除非 在init function 中有重新產生大量暫存資料
看來 luafilter init 中重覆性的工作 要減少,前置處理資料放在 module file 應可加速 luafilter 初始化 和 重覆產生 要回收的資料

-- module file
local data = nil

local function init_data()
--產生大量回收資料
end
local M={}

function M.init(env)
    data =  and data or  init_data()   -- 只會發生在require  載入file 時
end

-- ....

return M
'''

@shewer

shewer commented May 3, 2026

Copy link
Copy Markdown
Contributor

大概知道你說的了,靜態資料也會GC檢查, LUA_GCCOLLECT 還是少用爲妙
用 userdb (table or leveldb : c++ 側 參考 types_ext.cc UserDBREG ) or sqlite3 應該可行

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants