-
Notifications
You must be signed in to change notification settings - Fork 4.2k
CodeCache
skynet 修改了 Lua 的官方实现(可选),加入了一个新特性,可以让多个 Lua VM 共享相同的函数原型1。当在同一个 skynet 进程中开启了大量 lua VM 时,这个特性可以节省不少内存,且提高了 VM 启动速度。
Skynet changed the default implementation of Lua and introduced a new feature that can make Lua VM share the same function prototypes1. When many Lua VM instances are created in the same Skynet process, this feature will greatly reduce memory consumption and will improve the VM start time.
这个特性的使用,对一般用户来说是透明的。它改写了 lua 的辅助 API luaL_loadfilex
,所有直接或间接调用这个 api 都会受其影响。比如:loadfile 、require 等。它以文件名做 key ,一旦检索到之前有加载过相同文件名的 lua 文件,则从内存中找到之前的函数原型替代。注:Lua 函数是由函数原型以及 0 或多个 upvalue 绑定而成。
This feature is implicit to most users. It changes the auxiliary API luaL_loadfilex
, it will affect all direct calls or indirect calls. For example, loadfile
, require
, etc. It uses the file name as the key, once it finds the same Lua file has been loaded, it will load the existing prototype and replace it. Note: Luas function is consists of prototypes and 0 or more upvalue
bindings.
loadstring 不受其影响。所以,如果你需要多次加载一份 lua 文件,可以使用 io.open 打开文件,并使用 load 加载。
loadstring
is not affected by this change. So, if you want to load the same Lua file, io.open
can be used to open the file and use load
to load it.
代码缓存采用只增加不删除的策略,也就是说,一旦你加载过一份脚本,那么到进程结束前,它占据的内存永远不会释放(也不会被加载多次)。在大多数情况下,这不会有问题。
Loading cache uses adding without deleting strategy, which means, once you load a copy of the script, it will not be freed (and will not be reloaded) for the lifetime of the process. In most cases, it works fine without a problem.
skynet 留出了接口清理缓存,以做一些调试工作。接口模块叫做 skynet.codecache 。
Skynet also provides an interface to clean up the cached memory for debugging purposes, the name of the module is called skynet.codecache
.
local cache = require "skynet.codecache"
cache.clear()
这样就可以清理掉代码缓存。这个 api 是线程安全的,且老版本的数据依旧在内存中(可能被引用)。但需注意,单纯靠清理缓存的方式做热更新的方案是不完备的。这个完备性和是否引入这个特性无关。因为当你的系统在加载一批 lua 脚本时,单靠源文件的更新,无法保证这批脚本加载的原子性。(有部分是旧版本的,有部分是新版本的)
This will clean up the code memory cache. It's a thread-safe API and the previous version of data can still be referenced in memory. Note: it's incomplete to use this feature for hot-patch. The completeness isn't related to introducing this feature. Because when reloading a set of Lua scripts, it's not guaranteed it'll be an atomic operation. (some of the scripts might be old versions while the others might be updated to new version)
注意,codecache.clear() 仅仅只是创建一个新的 cache ( api 名字容易引起误会),而不释放内存。所以不要频繁调用。如果你需要你加载文件不受 cache 影响,正确的方式是自己读出代码文本,并用 loadstring 方式加载;而不是在加载前调用 codecache.clear 。
Note, codecache.clear()
only creates a new cache (the name of API may cause some confusion), it will not free memory, so please don't call it multiple times. If the file you are about to load is not affected by the memory cache, the right way to do this is to load the script and then use loadstring
to load it instead of loading it after codecache.clear
call.
cache.mode(mode)
这个 API 可以修改 codecache 在当前服务中的工作模式。mode 可以是 "ON" "OFF" "EXIST" ,默认的 mode 为 "ON" 。
This API can change this mode of the codecache
of the current service. mode
can be one of these options: "ON" "OFF" "EXIST", the default is "ON".
- 当 mode 为 "ON" 的时候,当前服务 cache 一切加载 lua 代码文件的行为。
- When
mode
is set to "ON", the current service will cache all behaviors of loading Lua script files. - 当 mode 为 "OFF" 的时候,当前服务关闭任何重复利用 lua 代码文件的行为,即使在别的服务中曾经加载过同名文件。
- When
mode
is set to "OFF", the current service will close any behavior that reuses Lua code, even if other services might have loaded the same file name. - 当 mode 为 "EXIST" 的时候,当前服务在加载曾经在其它服务或自己的服务加载过同名文件时,复用之前的拷贝。但对新加载的文件则不进行 cache 。注:通常可以让 skynet 本身被 cache 。
- When
mode
is set to "EXIST", the current service will reuse the previous copy if it's already loaded the same file name by itself or other services. But it will not cache any new loading files. Note: this can cache Skynet itself.
当 api 参数为空时,返回当前的 mode 。
When API is set to empty, it will return its current mode
.
注意:由于默认模式是打开状态,所以你第一次调用 cache.mode 的所在文件一定是被 cache 的。
Note: because default mode is "ON", so the first time you call cache.mode
in a file, it will be cached for that file for sure.