lua-language-server
lua-language-server copied to clipboard
大工程使用了极多的内存
How are you using the lua-language-server?
Visual Studio Code Extension (sumneko.lua)
Which OS are you using?
Windows
What is the issue affecting?
Other
Expected Behaviour
工作区诊断完成后
Actual Behaviour
接近5000个文件加载完成后, 内存占用5G左右
Reproduction steps
- Go to
- Click
- See error
Additional Notes
No response
Log File
No response
目前确实是一个文件1M左右内存,以后有机会看看怎么优化。
这个大小是固定的吗? 还是某个功能占用的特别多? 我可以先关掉占用内存高的功能
固定的
固定的
如果文件大小固定的话,是不是生成的提示都写到同一个文件更好,减少文件数量同时降低内存消耗
应该和文件大小成正比,大部分情况下1个文件平均消耗1M内存。消耗的内存主要是解析文件以及对解析结果进行预处理和缓存导致的。
经过一些简单测试,大部分内存占用都来自解析文件生成的语法树,因为语法树格式是lua表形式,因此内存占用确实会很高,例如lua代码 {} 会被解析成 { type = 'table', start = 0, finish = 2 } 。前者只有2个字节大小,但生成的lua表有200多字节,放大了100倍。可能需要重新设计语法树结构才能解决这个问题。
经过一些简单测试,大部分内存占用都来自解析文件生成的语法树,因为语法树格式是lua表形式,因此内存占用确实会很高,例如lua代码
{}会被解析成{ type = 'table', start = 0, finish = 2 }。前者只有2个字节大小,但生成的lua表有200多字节内存占用,放大了100倍。可能需要重新设计语法树结构才能解决这个问题。
这样治标不治本,可以试着让一部分不重要的语法树不在内存中,实际上5k文件里面常用的就几十几百,大部分解析的结果只需要作为api提示。所以可以进一步设定长期工作目录,其他的不重要的目录,不缓存语法树,甚至文件内容都不缓存。
这样治标不治本,可以试着让一部分不重要的语法树不在内存中,实际上5k文件里面常用的就几十几百,大部分解析的结果只需要作为api提示。所以可以进一步设定长期工作目录,其他的不重要的目录,不缓存语法树,甚至文件内容都不缓存。
我目前会将语义和语法树部分节点互相绑定,因此只有当一个文件完全没有使用任何全局变量以及 ---@class 或 ---@type 时我才能安全释放这个文件的内存。
不过想了想,这年头内存又不值钱,5000个文件的巨大工作目录总是要付出一些代价的,请自己尝试忽略掉无用的文件或是加内存吧。
5G内存也算多吗
我加入了一个实验性的功能,可以将未打开的文件的语法树生成到硬盘上而不是内存中,经测试这可以节省大约一半的内存,但是代价是初始化工作目录需要花费较长的时间,我的电脑上测试下来1秒只能编译20个文件。
启用方法是在启动参数中加入 --lazy (VSCode设置为 misc.parameters)。
另外如果你不需要的话可以关闭工作区诊断(将 diagnostics.workspaceDelay 设置为 -1),这也可以节省一半以上的内存。
问题相同,在公司开发没法控制开发环境的内存配置,希望能优化插件的内存占用。
或许可以利用luac 改造 ldump.c 使用lua原生的语法解析器, 将lua语法树数据提供给插件, c结构体占用内存更少, 解析器速度可以更快。
或许可以利用luac 改造 ldump.c 使用lua原生的语法解析器, 将lua语法树数据提供给插件, c结构体占用内存更少, 解析器速度可以更快。
不可能使用原生的,要做也把LuaParser用C重写一遍。两边生成的语法树结构完全不一样。
还有个办法就是 改成luajit, ast使用的 table 全部用 ffi + struct 来实现 这样也能降低内存 加快速度
还有个办法就是 改成luajit, ast使用的 table 全部用 ffi + struct 来实现 这样也能降低内存 加快速度
你这个目的是和重新设计结构一样的,我自己设计一个压缩格式用字节流一样能实现。 LuaJIT一方面我是用的运行时不支持,另一方面JIT本来就是用空间换时间的方案,占用的内存理论上会更多。
我加入了一个实验性的功能,可以将未打开的文件的语法树生成到硬盘上而不是内存中,经测试这可以节省大约一半的内存,但是代价是初始化工作目录需要花费较长的时间,我的电脑上测试下来1秒只能编译20个文件。
启用方法是在启动参数中加入
--lazy(VSCode设置为misc.parameters)。另外如果你不需要的话可以关闭工作区诊断(将
diagnostics.workspaceDelay设置为 -1),这也可以节省一半以上的内存。
1: --lazy 这个在哪个版本开始生效?
2: 我的电脑上测试下来1秒只能编译20个文件。 我这边是i5-12400, 不使用lazy参数的情况下, 每秒也只能编译10个文件左右
3.5.4或3.6.0吧。 你可以先从ci里下载最新的版本尝试一下:https://github.com/sumneko/lua-language-server/actions/runs/2977600473 解压覆盖本地的插件文件即可
谢谢, 内存确实少了快一半, 就是解析速度有点慢
谢谢, 内存确实少了快一半, 就是解析速度有点慢
嗯,所以实用性不高,除非我继续搞个持久性缓存,可以复用你上次启动语言服务时的本地缓存,这样就只有第一次要解析这么久。不过我还是觉得这么复杂的方案换这么点内存不值得,建议你联系你公司的IT帮你加根内存条。
谢谢, 内存确实少了快一半, 就是解析速度有点慢
嗯,所以实用性不高,除非我继续搞个持久性缓存,可以复用你上次启动语言服务时的本地缓存,这样就只有第一次要解析这么久。不过我还是觉得这么复杂的方案换这么点内存不值得,建议你联系你公司的IT帮你加根内存条。
这个比较难, 因为组里人比较多, 寡而不均最麻烦; 现在只能先用这个方案替代一下. (内存现在也有16G, 系统, 业务, 其他本地软件都需要一部分内存, 开了插件(占用内存6G以上)内存使用率就会到90%以上, 导致系统一卡一卡的)
谢谢, 内存确实少了快一半, 就是解析速度有点慢
嗯,所以实用性不高,除非我继续搞个持久性缓存,可以复用你上次启动语言服务时的本地缓存,这样就只有第一次要解析这么久。不过我还是觉得这么复杂的方案换这么点内存不值得,建议你联系你公司的IT帮你加根内存条。
这个比较难, 因为组里人比较多, 寡而不均最麻烦; 现在只能先用这个方案替代一下. (内存现在也有16G, 系统, 业务, 其他本地软件都需要一部分内存, 开了插件(占用内存6G以上)内存使用率就会到90%以上, 导致系统一卡一卡的)
俺也一样
5000个文件。。。。还用lua写啊。。这不换语言?
精力有限,暂时不打算进一步关注内存问题。你可以先把工作区诊断关掉试试。