|
|
- --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
|