先看一个例子
1. 实际例子
- 先造一个100M的文件,文件名为:test-100M。
dd if=/dev/urandom of=test1 bs=1M count=10
- 写一段lua程序读取这个文件。命名为test.lua
local function load_file(path)
if not path then
return nil
end
-- 以只读方式打开文件
local file = io.open(path, "r")
local content = file:read("*all")
io.close(file)
end
load_file("test-100M")
while (true)
do
end
- 使用ps aux 名检测这个进程的内存变化情况。
while true; do ps aux | grep test.lua; sleep 1; done
可以看到test.lua进程物理内存消耗了399468kb = 390M
显然在实际场景中,这样的内存消耗是不能接受的,更要命的是在 load_file调用完成后,内存一直没有降下来。
2. 优化过程
通过刚才例子可以看出,test.lua存在两个问题,1. 内存消耗过大。 2. 内存消耗以后一直没有释放。
解决第一个问题思路是重写lua read函数,自己用c实现。
今天重点讨论第二个,怎么在高内存消耗以后,及时的释放掉内存?
-
主动调用lua垃圾回收函数
通过调用collectgarbage(“collect”) 显示的去回收内存。 这样做是可以释放掉一部分内存,但由于lua虚拟机出于对内存效率的需要,不会将所有内存都还给操作系统。具体情况可以自己实验下。 -
将内存消耗过大的操作单独起系统命令执行,设置超时时间,执行完成,进程退出,由操作系统回收这块内存。
-
其它,如果消耗内存的操作不是读文件,而是像字符串拼接、table。那么可以使用table弱表。 字符串拼接可以用table.concat提高内存回收效率。
3. 优化成果展示
优化后的代码(这里选用主动垃圾回收的方式)
local function load_file(path)
if not path then
return nil
end
-- 以只读方式打开文件
local file = io.open(path, "r")
local content = file:read("*all")
io.close(file)
end
load_file("test-100M")
while (true)
do
end
local mem1 = collectgarbage("count")
print("初始内存:", mem1, "kb")
load_file()
local mem3 = collectgarbage("count")
print("\n垃圾收集1次:", mem3, "kb")
collectgarbage("collect")
collectgarbage("collect")
collectgarbage("collect")
local mem4 = collectgarbage("count")
print("\n垃圾收集2次:", mem4, "kb")
while (true)
do
end
内存占用情况统计: