源战役客户端
Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.
 
 
 
 
 

460 linhas
16 KiB

--lua内存管理器 定时清理没有被引用的对象
LuaMemManager = LuaMemManager or BaseClass(nil, true)
local rawset = rawset
local rawget = rawget
local LuaMemManager = LuaMemManager
local Time = Time
local string = string
local string_gsub = string.gsub
local string_sub = string.sub
local string_find = string.find
local string_len = string.len
local table_insert = table.insert
local package_loaded = package.loaded
local table_insert = table.insert
local table_remove = table.remove
--直接加载的匹配规则
LuaMemManager.DIRECT_REQUIRE_CLASS_LIST = {
-- "^game%.common%."
-- ,"^game%.scene%."
{"EventName",-9}
,{"UiFactory",-9}
,{"UIHelper",-8}
,{"UIObjPool",-9}
,{"GameDefine",-10}
,{"GlobalEvents",-12}
,{"scripts",-7}
,{"UIProperty",-10}
,{"Scene",-5}
,{"SceneConfig",-11}
,{"PoseState",-9}
,{"Controller",-10}
,{"Ctrl",-4}
,{"ChatController_TWO",-18}
,{"TweenLite",-9}
,{"CookieWrapper",-13}
,{"CheatCommand",-12}
,{"Util", -4}
-- ,"Helper"}
,{"module",-6}
,{"Module",-6}
,{"Require",-7}
,{"Require",0}
,{"Manager",-7}
,{"Mgr",-3}
-- ,"Effect"}
,{"MainRoleVo",-10}
,{"Requires",-8}
,{"Model",-5}
,{"Action",1}
,{"Jury",1}
,{"Const",-5}--不加的话会经常被释放啊
,{"Functor", 1}
,{"UIComponents", 1}
,{"ItemListCreator", 1}
,{"Test", 1}
}
--重新登录不清除缓存的model
LuaMemManager.KEEP_CACHE_MODEL = {
["LoginModel"] = true,
["ServerModel"] = true,
["UIModelClassByRT"] = true,
["BaseModel"] = true,
["GameSettingModel"] = true,
}
function LuaMemManager:ForceReload()
package_loaded["utils.ReloadModules"] = nil
originalRequire("utils.ReloadModules")
for i,v in ipairs(ReloadModules.Names) do
package_loaded[v] = nil
if not self:checkClassStatus(v) then
originalRequire(v)
logWarn("ForceReload:Reload Module=>Reload "..v.." successfuly!!")
else
local class_name = LuaMemManager.GetLastStr(v,".")
local ct = self.class_list[class_name]
if not ct then
logWarn("ForceReload:Reload Module:Module=> "..v.." has not been required yet!!")
originalRequire(v)
else
if not ct.isLoad then
ct.isLoad = true
ct.last_used_Time = Time.time
end
logWarn("ForceReload:Reload Module=>Reload "..v.." successfuly!!")
originalRequire(v)
end
end
end
ReloadModules.ReloadCommand()
end
function LuaMemManager:__init()
LuaMemManager.Instance = self
self.clear_mem_start_time = 0
self:initConfigInfo()
self:initGameClassInfo()
collectgarbage("setpause", 110)
collectgarbage("setstepmul", 200)
--重写require
local function moduleRequire(config_path,config_name, auto_delete_time, cannot_force_delete)
--保存配置文件信息
if config_name then
if not self.config_list[config_name] then
self.config_list[config_name] = {isLoad = false, config_path = config_path, last_used_Time = 0}
if auto_delete_time then
self.config_list[config_name].auto_delete_time = auto_delete_time
end
if cannot_force_delete then
self.config_list[config_name].cannot_force_delete = cannot_force_delete
end
end
if auto_delete_time and cannot_force_delete then
if Config[config_name] then end
end
return nil
end
--保存代理类信息
local class_name = LuaMemManager.GetLastStr(config_path,".")
--保存普通类信息
if class_name and (string_find(config_path,"game.",1,true) == 1
or string_find(config_path,"sysinfo.",1,true) == 1
or string_find(config_path,"utils.",1,true) == 1
or string_find(config_path,"gameinput.",1,true) == 1
or string_find(config_path,"Language.",1,true) == 1
or string_find(config_path,"operation.",1,true) == 1
or string_find(config_path,"newgameui.",1,true) == 1
or string_find(config_path,"UIComponent.",1,true) == 1) and LuaMemManager.checkClassStatus(self, config_path) then
if self.class_list[class_name] == nil then
self.class_list[class_name] = {isLoad = false, config_path = config_path, last_used_Time = 0}
end
return nil
end
if string_find(config_path,"Model",-5,true) then
self.model_list[class_name] = {isLoad = false, config_path = config_path}
end
originalRequire(config_path)
end
_G.originalRequire = _G.require
_G.require = moduleRequire
end
function LuaMemManager:InitInfo()
local function onUpdateFunc()
self:checkToReleaseMem()
end
TimerQuest.AddPeriodQuest(GlobalTimerQuest, onUpdateFunc, 55, -1)
end
function LuaMemManager:ClearMemory()
-- print("强制垃圾回收")
-- collectgarbage("collect")
collectgarbage()
end
function LuaMemManager:getInstance()
if LuaMemManager.Instance == nil then
LuaMemManager.New()
end
return LuaMemManager.Instance
end
--将 szFullString 对象拆分为一个子字符串表
function LuaMemManager.Split(szFullString, szSeparator)
local nFindStartIndex = 1
local nSplitIndex = 1
local nSplitArray = {}
while true do
local nFindLastIndex = string_find(szFullString, szSeparator, nFindStartIndex,true)
if not nFindLastIndex then
nSplitArray[nSplitIndex] = string_sub(szFullString, nFindStartIndex, string_len(szFullString))
break
end
table_insert(nSplitArray, string_sub(szFullString, nFindStartIndex, nFindLastIndex - 1))
nFindStartIndex = nFindLastIndex + string_len(szSeparator)
nSplitIndex = nSplitIndex + 1
end
return nSplitArray
end
--获取最后一个字符串
function LuaMemManager.GetLastStr(szFullString, szSeparator)
local nFindStartIndex = 1
local nSplitIndex = 1
while true do
local nFindLastIndex = string_find(szFullString, szSeparator, nFindStartIndex,true)
if not nFindLastIndex then
return string_sub(szFullString, nFindStartIndex, string_len(szFullString))
end
nFindStartIndex = nFindLastIndex + string_len(szSeparator)
nSplitIndex = nSplitIndex + 1
end
end
--初始化配置信息
function LuaMemManager:initConfigInfo()
self.check_config_time = 0
--Config为所有配置属性的父节点
Config = Config or {}
self.config_list = {}
self.model_list = {}
setmetatable(Config,{__newindex = function (t,k,v)
rawset(Config,k,v)
if v == nil then
LuaMemManager.resetPackageLoaded(self, k)
end
end
,
__index = function (t,k)
local ct = self.config_list[k]
if ct and not ct.isLoad then
-- print("------------------------创建配置 ",k)
ct.isLoad = true
ct.last_used_Time = Time.time
originalRequire(ct.config_path)
end
return rawget(Config,k)
end}
)
end
--初始化类的信息
function LuaMemManager:initGameClassInfo()
self.check_class_time = 0
self.class_list = {}
--_G为所有全局变量的父节点
setmetatable(_G,{__newindex = function (t,k,v)
-- if k == "data" then
-- local info = debug.getinfo(2, "Sl")
-- print("全局变量:" .. k .. ", 来源:"..info.source)
-- end
if v == nil then
local ct = self.class_list[k]
if ct then
ct.isLoad = false
if package_loaded[ct.config_path] then
package_loaded[ct.config_path] = nil
end
end
end
rawset(_G ,k ,v)
end
,
__index = function (t,k)
local ct = self.class_list[k]
if ct and not ct.isLoad then
-- print("创建类 ",k)
ct.isLoad = true
ct.last_used_Time = Time.time
originalRequire(ct.config_path)
end
return rawget(_G ,k)
end}
)
end
--检测是否是需要处理的类文件
function LuaMemManager:checkClassStatus(config_path)
for i,vo in pairs(LuaMemManager.DIRECT_REQUIRE_CLASS_LIST) do
if string_find(config_path,vo[1],vo[2],true) then
return false
end
end
return true
end
--把配置对象置空
function LuaMemManager:clearConfigPro(class_name)
Config[class_name] = nil
LuaMemManager.resetPackageLoaded(self, class_name)
end
--去掉配置对象在package的引用
function LuaMemManager:resetPackageLoaded(class_name)
local ct = self.config_list[class_name]
if ct then
-- print("销毁配置 ",class_name)
ct.isLoad = false
if package_loaded[ct.config_path] then
package_loaded[ct.config_path] = nil
end
end
end
--清理类对象
function LuaMemManager:clearGameClass(class_type)
if class_type then
local now_super = class_type
local delete_list = nil
local child_will_delete = true
local t = nil
local class_name = nil
while now_super ~= nil do
-- print("now_super._source=",now_super._source)
if now_super._source then
class_name = LuaMemManager.GetLastStr(now_super._source,"/")
class_name = string_gsub(class_name,".lua","")
if class_name and self.class_list[class_name] then
if child_will_delete then --只有子类要被删除 才去判断父类是否需要去掉一个作为父类的引用
if _be_super_count_map[now_super] then
_be_super_count_map[now_super] = _be_super_count_map[now_super] - 1
end
--如果该类引用的实力对象的引用次数为0 而且 该类没有作为任何类的父类 才需要被删除
if (_in_obj_ins_map[now_super] == nil or _G.next(_in_obj_ins_map[now_super]) == nil) and (_be_super_count_map[now_super] == nil or _be_super_count_map[now_super] == 0) then
delete_list = delete_list or {}
table_insert(delete_list,class_name)
child_will_delete = true
else
child_will_delete = false
end
end
end
end
now_super = now_super.super
end
if delete_list then
for i = 1,#delete_list do
-- print("销毁类 ",delete_list[i])
LuaMemManager.resetGameClassPackageLoaded(self, delete_list[i])
_G[delete_list[i]] = nil
end
end
end
return false
end
--清理类对象在package的引用
function LuaMemManager:resetGameClassPackageLoaded(className)
local ct = self.class_list[className]
if ct then
ct.isLoad = false
if package_loaded[ct.config_path] then
package_loaded[ct.config_path] = nil
end
end
end
function LuaMemManager:checkToReleaseMem(forceToRelease, hot_update)
--检测配置是否需要释放内存
forceToRelease = forceToRelease or hot_update
if forceToRelease or (self.check_config_time == 0 or Time.time - self.check_config_time > 100) then --检测是否有需要清理的配置对象
self.check_config_time = Time.time
local can_force_release = forceToRelease
for class_name,vo in pairs(self.config_list) do
if vo.isLoad then
if not hot_update and vo.cannot_force_delete then
can_force_release = false
end
if can_force_release then
if Time.time - vo.last_used_Time < 0.5 then --0.5秒的最大限度加载时间
can_force_release = false
end
end
if can_force_release or (Time.time - vo.last_used_Time > (vo.auto_delete_time or 100)) then --5秒没被引用就销毁
LuaMemManager.clearConfigPro(self, class_name)
end
end
end
end
--检测类是否需要释放内存
if forceToRelease or ((self.check_class_time == 0 or Time.time - self.check_class_time >= 50)) then --检测是否有需要清理的类对象 调试阶段先用1
self.check_class_time = Time.time
local class_type = nil
for class_name,vo in pairs(self.class_list) do
if vo.isLoad then--当前已经被加载
if Time.time - vo.last_used_Time > 0.5 then --0.5秒的最大限度加载时间
class_type = _G[class_name]
if class_type
and (_be_super_count_map[class_type] == nil or _be_super_count_map[class_type] == 0) --没有作为父类的引用
and (_in_obj_ins_map[class_type] == nil or _G.next(_in_obj_ins_map[class_type]) == nil)--没有实例化的对象
then
LuaMemManager.clearGameClass(self, class_type)
end
end
end
end
end
if forceToRelease then -- or self.clear_mem_start_time == 0 or Time.time - self.clear_mem_start_time >= 3 then
-- self.clear_mem_start_time = Time.time
--if forceToRelease or collectgarbage("count") > 20000 then
LuaMemManager.ClearMemory()
-- end
end
end
--清除所有model的缓存
function LuaMemManager:ClearModelData( )
for class_name,v in pairs(self.model_list) do
if not LuaMemManager.KEEP_CACHE_MODEL[class_name] and _G[class_name]
and _G[class_name].Instance then
--执行init函数
local instance = _G[class_name].Instance
instance._class_type.__init(instance)
end
end
end
--[[
--清除所有model的缓存
function LuaMemManager:ClearModelData( )
if self.is_clearing_model then
return
end
self.delay_clear_model_list = {}
for class_name,v in pairs(self.model_list) do
table_insert(self.delay_clear_model_list, class_name)
end
self.is_clearing_model = true
local function on_update( )
self:ClearModelOnUpdate()
end
if not self.period_clear_id then
self.period_clear_id = GlobalTimerQuest:AddPeriodQuest(on_update, 0.02, -1)
end
end
function LuaMemManager:ClearModelOnUpdate( )
local size = #self.delay_clear_model_list
if size > 0 then
local len = 3
for i = 1, len do
local class_name = table_remove(self.delay_clear_model_list, 1)
if class_name and not LuaMemManager.KEEP_CACHE_MODEL[class_name] and _G[class_name]
and _G[class_name].Instance then
--执行init函数
local instance = _G[class_name].Instance
instance._class_type.__init(instance)
end
end
else
if self.period_clear_id then
GlobalTimerQuest:CancelQuest(self.period_clear_id)
self.period_clear_id = nil
end
self.is_clearing_model = false
end
end
]]
function LuaMemManager:__delete()
end