MEMORY_D = {}
setmetatable(MEMORY_D, {__index = _G})
local _ENV = MEMORY_D
local mxc
local callback
local callback_arg
local YIELD_TIME = 5000
local cur_times = 0
local function search_self(node, node_map)
if node_map[node] then
return true
end
end
local function search_leak(node, parent, obj, result, parent_path, search_record, check_weak)
local current_path
local mt, key_weak, value_weak
local node_map = parent
node_map[node] = true
mt = debug.getmetatable(node)
if mt then
if mt["__mode"] then
if string.find(mt["__mode"], "k") then
key_weak = true
end
if string.find(mt["__mode"], "v") then
value_weak = true
end
end
end
if not check_weak and key_weak and value_weak then
return
end
if cur_times >= YIELD_TIME then
if type(mxc) == "thread" then
cur_times = 0
coroutine.yield()
end
else
cur_times = cur_times + 1
end
for k, v in pairs(node) do
if type(k) == "table" and (check_weak or not key_weak)then
current_path = parent_path .. "/" .. "key-is-table"
if obj == k then
result[#result + 1] = current_path
else
if not search_self(k, node_map) then
search_leak(k, node_map, obj, result, current_path, search_record, check_weak)
end
mt = debug.getmetatable(k)
if mt then
if not search_self(mt, node_map) then
search_leak(mt, node_map, obj, result, current_path, search_record, check_weak)
end
end
end
elseif is_string(k) or is_int(k) then
current_path = parent_path .. "/" .. k
else
current_path = parent_path .. "/other type"
end
if type(v) == "table" and (check_weak or not value_weak)then
if obj == v then
result[#result + 1] = current_path
else
if not search_self(v, node_map) then
search_leak(v, node_map, obj, result, current_path, search_record, check_weak)
end
mt = debug.getmetatable(v)
if mt then
if not search_self(mt, node_map) then
search_leak(mt, node_map, obj, result, current_path, search_record, check_weak)
end
end
end
elseif type(v) == "function" then
if not search_record[v] then
search_record[v] = true
local fupv = get_func_upvalue(v)
if fupv then
search_leak(fupv, node_map, obj, result, current_path, search_record, check_weak)
end
local fenv = debug.getfenv(v)
if not search_self(fenv, node_map) then
search_leak(fenv, node_map, obj, result, current_path, search_record, check_weak)
end
local freg = debug.getregistry(v)
if not search_self(freg, node_map) then
search_leak(freg, node_map, obj, result, current_path, search_record, check_weak)
end
mt = debug.getmetatable(v)
if mt then
if not search_self(mt, node_map) then
search_leak(mt, node_map, obj, result, current_path, search_record, check_weak)
end
end
end
end
end
end
function get_func_upvalue(func)
local tbl = {}
local n = 1
while true do
local name, value = debug.getupvalue(func,n)
if not name then
break
end
if value == nil then
value = {}
end
tbl[name] = value
n= n + 1
end
return tbl
end
function check_leak_obj(obj, check_weak)
local result = {}
local search_record = {}
local parent_path = "_G"
search_leak(_G, {}, obj, result, parent_path, search_record, check_weak)
return result
end
function get_leak_obj_list()
collectgarbage("collect")
return (get_all_destructed_obs())
end
function check_leak_obj_refs(raiser, check_weak)
local leak_object_list = get_leak_obj_list()
if sizeof(leak_object_list) == 0 then
print("无内存泄漏\n")
write_log("无内存泄漏\n")
return
end
local result = {}
local search_record = {}
local parent_path = "_G"
for _, obj in pairs(leak_object_list) do
search_leak(_G, {}, obj, result, parent_path, search_record, check_weak)
if sizeof(result) > 0 then
result["leak"] = watch(obj)
if not raiser then
print("%o", result)
else
local str_result = string.format("Error: %s\n", save_string(result))
write_log(str_result)
end
end
result = {}
search_record= {}
end
end
function get_leak_obj_refs(raiser, check_weak, f, f_arg)
if not mxc then
mxc = coroutine.create(function (val_a, val_b)
check_leak_obj_refs(val_a, val_b) end)
if type(mxc) == "thread" then
callback = f
callback_arg = f_arg
resume_timer(raiser, check_weak)
end
end
end
function resume_timer(a, b)
if type(mxc) == "thread" then
if coroutine.status(mxc) == "suspended" then
coroutine.resume(mxc, a, b)
elseif coroutine.status(mxc) == "dead" then
mxc = nil
cur_times = 0
if is_function(callback) and is_table(callback_arg) then
callback(callback_arg[1], callback_arg[2])
end
return
end
end
set_timer(5, resume_timer)
end
function create()
end
create()