源战役客户端
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

460 lines
16 KiB

  1. --lua内存管理器 定时清理没有被引用的对象
  2. LuaMemManager = LuaMemManager or BaseClass(nil, true)
  3. local rawset = rawset
  4. local rawget = rawget
  5. local LuaMemManager = LuaMemManager
  6. local Time = Time
  7. local string = string
  8. local string_gsub = string.gsub
  9. local string_sub = string.sub
  10. local string_find = string.find
  11. local string_len = string.len
  12. local table_insert = table.insert
  13. local package_loaded = package.loaded
  14. local table_insert = table.insert
  15. local table_remove = table.remove
  16. --直接加载的匹配规则
  17. LuaMemManager.DIRECT_REQUIRE_CLASS_LIST = {
  18. -- "^game%.common%."
  19. -- ,"^game%.scene%."
  20. {"EventName",-9}
  21. ,{"UiFactory",-9}
  22. ,{"UIHelper",-8}
  23. ,{"UIObjPool",-9}
  24. ,{"GameDefine",-10}
  25. ,{"GlobalEvents",-12}
  26. ,{"scripts",-7}
  27. ,{"UIProperty",-10}
  28. ,{"Scene",-5}
  29. ,{"SceneConfig",-11}
  30. ,{"PoseState",-9}
  31. ,{"Controller",-10}
  32. ,{"Ctrl",-4}
  33. ,{"ChatController_TWO",-18}
  34. ,{"TweenLite",-9}
  35. ,{"CookieWrapper",-13}
  36. ,{"CheatCommand",-12}
  37. ,{"Util", -4}
  38. -- ,"Helper"}
  39. ,{"module",-6}
  40. ,{"Module",-6}
  41. ,{"Require",-7}
  42. ,{"Require",0}
  43. ,{"Manager",-7}
  44. ,{"Mgr",-3}
  45. -- ,"Effect"}
  46. ,{"MainRoleVo",-10}
  47. ,{"Requires",-8}
  48. ,{"Model",-5}
  49. ,{"Action",1}
  50. ,{"Jury",1}
  51. ,{"Const",-5}--不加的话会经常被释放啊
  52. ,{"Functor", 1}
  53. ,{"UIComponents", 1}
  54. ,{"ItemListCreator", 1}
  55. ,{"Test", 1}
  56. }
  57. --重新登录不清除缓存的model
  58. LuaMemManager.KEEP_CACHE_MODEL = {
  59. ["LoginModel"] = true,
  60. ["ServerModel"] = true,
  61. ["UIModelClassByRT"] = true,
  62. ["BaseModel"] = true,
  63. ["GameSettingModel"] = true,
  64. }
  65. function LuaMemManager:ForceReload()
  66. package_loaded["utils.ReloadModules"] = nil
  67. originalRequire("utils.ReloadModules")
  68. for i,v in ipairs(ReloadModules.Names) do
  69. package_loaded[v] = nil
  70. if not self:checkClassStatus(v) then
  71. originalRequire(v)
  72. logWarn("ForceReload:Reload Module=>Reload "..v.." successfuly!!")
  73. else
  74. local class_name = LuaMemManager.GetLastStr(v,".")
  75. local ct = self.class_list[class_name]
  76. if not ct then
  77. logWarn("ForceReload:Reload Module:Module=> "..v.." has not been required yet!!")
  78. originalRequire(v)
  79. else
  80. if not ct.isLoad then
  81. ct.isLoad = true
  82. ct.last_used_Time = Time.time
  83. end
  84. logWarn("ForceReload:Reload Module=>Reload "..v.." successfuly!!")
  85. originalRequire(v)
  86. end
  87. end
  88. end
  89. ReloadModules.ReloadCommand()
  90. end
  91. function LuaMemManager:__init()
  92. LuaMemManager.Instance = self
  93. self.clear_mem_start_time = 0
  94. self:initConfigInfo()
  95. self:initGameClassInfo()
  96. collectgarbage("setpause", 110)
  97. collectgarbage("setstepmul", 200)
  98. --重写require
  99. local function moduleRequire(config_path,config_name, auto_delete_time, cannot_force_delete)
  100. --保存配置文件信息
  101. if config_name then
  102. if not self.config_list[config_name] then
  103. self.config_list[config_name] = {isLoad = false, config_path = config_path, last_used_Time = 0}
  104. if auto_delete_time then
  105. self.config_list[config_name].auto_delete_time = auto_delete_time
  106. end
  107. if cannot_force_delete then
  108. self.config_list[config_name].cannot_force_delete = cannot_force_delete
  109. end
  110. end
  111. if auto_delete_time and cannot_force_delete then
  112. if Config[config_name] then end
  113. end
  114. return nil
  115. end
  116. --保存代理类信息
  117. local class_name = LuaMemManager.GetLastStr(config_path,".")
  118. --保存普通类信息
  119. if class_name and (string_find(config_path,"game.",1,true) == 1
  120. or string_find(config_path,"sysinfo.",1,true) == 1
  121. or string_find(config_path,"utils.",1,true) == 1
  122. or string_find(config_path,"gameinput.",1,true) == 1
  123. or string_find(config_path,"Language.",1,true) == 1
  124. or string_find(config_path,"operation.",1,true) == 1
  125. or string_find(config_path,"newgameui.",1,true) == 1
  126. or string_find(config_path,"UIComponent.",1,true) == 1) and LuaMemManager.checkClassStatus(self, config_path) then
  127. if self.class_list[class_name] == nil then
  128. self.class_list[class_name] = {isLoad = false, config_path = config_path, last_used_Time = 0}
  129. end
  130. return nil
  131. end
  132. if string_find(config_path,"Model",-5,true) then
  133. self.model_list[class_name] = {isLoad = false, config_path = config_path}
  134. end
  135. originalRequire(config_path)
  136. end
  137. _G.originalRequire = _G.require
  138. _G.require = moduleRequire
  139. end
  140. function LuaMemManager:InitInfo()
  141. local function onUpdateFunc()
  142. self:checkToReleaseMem()
  143. end
  144. TimerQuest.AddPeriodQuest(GlobalTimerQuest, onUpdateFunc, 55, -1)
  145. end
  146. function LuaMemManager:ClearMemory()
  147. -- print("强制垃圾回收")
  148. -- collectgarbage("collect")
  149. collectgarbage()
  150. end
  151. function LuaMemManager:getInstance()
  152. if LuaMemManager.Instance == nil then
  153. LuaMemManager.New()
  154. end
  155. return LuaMemManager.Instance
  156. end
  157. --将 szFullString 对象拆分为一个子字符串表
  158. function LuaMemManager.Split(szFullString, szSeparator)
  159. local nFindStartIndex = 1
  160. local nSplitIndex = 1
  161. local nSplitArray = {}
  162. while true do
  163. local nFindLastIndex = string_find(szFullString, szSeparator, nFindStartIndex,true)
  164. if not nFindLastIndex then
  165. nSplitArray[nSplitIndex] = string_sub(szFullString, nFindStartIndex, string_len(szFullString))
  166. break
  167. end
  168. table_insert(nSplitArray, string_sub(szFullString, nFindStartIndex, nFindLastIndex - 1))
  169. nFindStartIndex = nFindLastIndex + string_len(szSeparator)
  170. nSplitIndex = nSplitIndex + 1
  171. end
  172. return nSplitArray
  173. end
  174. --获取最后一个字符串
  175. function LuaMemManager.GetLastStr(szFullString, szSeparator)
  176. local nFindStartIndex = 1
  177. local nSplitIndex = 1
  178. while true do
  179. local nFindLastIndex = string_find(szFullString, szSeparator, nFindStartIndex,true)
  180. if not nFindLastIndex then
  181. return string_sub(szFullString, nFindStartIndex, string_len(szFullString))
  182. end
  183. nFindStartIndex = nFindLastIndex + string_len(szSeparator)
  184. nSplitIndex = nSplitIndex + 1
  185. end
  186. end
  187. --初始化配置信息
  188. function LuaMemManager:initConfigInfo()
  189. self.check_config_time = 0
  190. --Config为所有配置属性的父节点
  191. Config = Config or {}
  192. self.config_list = {}
  193. self.model_list = {}
  194. setmetatable(Config,{__newindex = function (t,k,v)
  195. rawset(Config,k,v)
  196. if v == nil then
  197. LuaMemManager.resetPackageLoaded(self, k)
  198. end
  199. end
  200. ,
  201. __index = function (t,k)
  202. local ct = self.config_list[k]
  203. if ct and not ct.isLoad then
  204. -- print("------------------------创建配置 ",k)
  205. ct.isLoad = true
  206. ct.last_used_Time = Time.time
  207. originalRequire(ct.config_path)
  208. end
  209. return rawget(Config,k)
  210. end}
  211. )
  212. end
  213. --初始化类的信息
  214. function LuaMemManager:initGameClassInfo()
  215. self.check_class_time = 0
  216. self.class_list = {}
  217. --_G为所有全局变量的父节点
  218. setmetatable(_G,{__newindex = function (t,k,v)
  219. -- if k == "data" then
  220. -- local info = debug.getinfo(2, "Sl")
  221. -- print("全局变量:" .. k .. ", 来源:"..info.source)
  222. -- end
  223. if v == nil then
  224. local ct = self.class_list[k]
  225. if ct then
  226. ct.isLoad = false
  227. if package_loaded[ct.config_path] then
  228. package_loaded[ct.config_path] = nil
  229. end
  230. end
  231. end
  232. rawset(_G ,k ,v)
  233. end
  234. ,
  235. __index = function (t,k)
  236. local ct = self.class_list[k]
  237. if ct and not ct.isLoad then
  238. -- print("创建类 ",k)
  239. ct.isLoad = true
  240. ct.last_used_Time = Time.time
  241. originalRequire(ct.config_path)
  242. end
  243. return rawget(_G ,k)
  244. end}
  245. )
  246. end
  247. --检测是否是需要处理的类文件
  248. function LuaMemManager:checkClassStatus(config_path)
  249. for i,vo in pairs(LuaMemManager.DIRECT_REQUIRE_CLASS_LIST) do
  250. if string_find(config_path,vo[1],vo[2],true) then
  251. return false
  252. end
  253. end
  254. return true
  255. end
  256. --把配置对象置空
  257. function LuaMemManager:clearConfigPro(class_name)
  258. Config[class_name] = nil
  259. LuaMemManager.resetPackageLoaded(self, class_name)
  260. end
  261. --去掉配置对象在package的引用
  262. function LuaMemManager:resetPackageLoaded(class_name)
  263. local ct = self.config_list[class_name]
  264. if ct then
  265. -- print("销毁配置 ",class_name)
  266. ct.isLoad = false
  267. if package_loaded[ct.config_path] then
  268. package_loaded[ct.config_path] = nil
  269. end
  270. end
  271. end
  272. --清理类对象
  273. function LuaMemManager:clearGameClass(class_type)
  274. if class_type then
  275. local now_super = class_type
  276. local delete_list = nil
  277. local child_will_delete = true
  278. local t = nil
  279. local class_name = nil
  280. while now_super ~= nil do
  281. -- print("now_super._source=",now_super._source)
  282. if now_super._source then
  283. class_name = LuaMemManager.GetLastStr(now_super._source,"/")
  284. class_name = string_gsub(class_name,".lua","")
  285. if class_name and self.class_list[class_name] then
  286. if child_will_delete then --只有子类要被删除 才去判断父类是否需要去掉一个作为父类的引用
  287. if _be_super_count_map[now_super] then
  288. _be_super_count_map[now_super] = _be_super_count_map[now_super] - 1
  289. end
  290. --如果该类引用的实力对象的引用次数为0 而且 该类没有作为任何类的父类 才需要被删除
  291. 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
  292. delete_list = delete_list or {}
  293. table_insert(delete_list,class_name)
  294. child_will_delete = true
  295. else
  296. child_will_delete = false
  297. end
  298. end
  299. end
  300. end
  301. now_super = now_super.super
  302. end
  303. if delete_list then
  304. for i = 1,#delete_list do
  305. -- print("销毁类 ",delete_list[i])
  306. LuaMemManager.resetGameClassPackageLoaded(self, delete_list[i])
  307. _G[delete_list[i]] = nil
  308. end
  309. end
  310. end
  311. return false
  312. end
  313. --清理类对象在package的引用
  314. function LuaMemManager:resetGameClassPackageLoaded(className)
  315. local ct = self.class_list[className]
  316. if ct then
  317. ct.isLoad = false
  318. if package_loaded[ct.config_path] then
  319. package_loaded[ct.config_path] = nil
  320. end
  321. end
  322. end
  323. function LuaMemManager:checkToReleaseMem(forceToRelease, hot_update)
  324. --检测配置是否需要释放内存
  325. forceToRelease = forceToRelease or hot_update
  326. if forceToRelease or (self.check_config_time == 0 or Time.time - self.check_config_time > 100) then --检测是否有需要清理的配置对象
  327. self.check_config_time = Time.time
  328. local can_force_release = forceToRelease
  329. for class_name,vo in pairs(self.config_list) do
  330. if vo.isLoad then
  331. if not hot_update and vo.cannot_force_delete then
  332. can_force_release = false
  333. end
  334. if can_force_release then
  335. if Time.time - vo.last_used_Time < 0.5 then --0.5秒的最大限度加载时间
  336. can_force_release = false
  337. end
  338. end
  339. if can_force_release or (Time.time - vo.last_used_Time > (vo.auto_delete_time or 100)) then --5秒没被引用就销毁
  340. LuaMemManager.clearConfigPro(self, class_name)
  341. end
  342. end
  343. end
  344. end
  345. --检测类是否需要释放内存
  346. if forceToRelease or ((self.check_class_time == 0 or Time.time - self.check_class_time >= 50)) then --检测是否有需要清理的类对象 调试阶段先用1
  347. self.check_class_time = Time.time
  348. local class_type = nil
  349. for class_name,vo in pairs(self.class_list) do
  350. if vo.isLoad then--当前已经被加载
  351. if Time.time - vo.last_used_Time > 0.5 then --0.5秒的最大限度加载时间
  352. class_type = _G[class_name]
  353. if class_type
  354. and (_be_super_count_map[class_type] == nil or _be_super_count_map[class_type] == 0) --没有作为父类的引用
  355. and (_in_obj_ins_map[class_type] == nil or _G.next(_in_obj_ins_map[class_type]) == nil)--没有实例化的对象
  356. then
  357. LuaMemManager.clearGameClass(self, class_type)
  358. end
  359. end
  360. end
  361. end
  362. end
  363. if forceToRelease then -- or self.clear_mem_start_time == 0 or Time.time - self.clear_mem_start_time >= 3 then
  364. -- self.clear_mem_start_time = Time.time
  365. --if forceToRelease or collectgarbage("count") > 20000 then
  366. LuaMemManager.ClearMemory()
  367. -- end
  368. end
  369. end
  370. --清除所有model的缓存
  371. function LuaMemManager:ClearModelData( )
  372. for class_name,v in pairs(self.model_list) do
  373. if not LuaMemManager.KEEP_CACHE_MODEL[class_name] and _G[class_name]
  374. and _G[class_name].Instance then
  375. --执行init函数
  376. local instance = _G[class_name].Instance
  377. instance._class_type.__init(instance)
  378. end
  379. end
  380. end
  381. --[[
  382. --清除所有model的缓存
  383. function LuaMemManager:ClearModelData( )
  384. if self.is_clearing_model then
  385. return
  386. end
  387. self.delay_clear_model_list = {}
  388. for class_name,v in pairs(self.model_list) do
  389. table_insert(self.delay_clear_model_list, class_name)
  390. end
  391. self.is_clearing_model = true
  392. local function on_update( )
  393. self:ClearModelOnUpdate()
  394. end
  395. if not self.period_clear_id then
  396. self.period_clear_id = GlobalTimerQuest:AddPeriodQuest(on_update, 0.02, -1)
  397. end
  398. end
  399. function LuaMemManager:ClearModelOnUpdate( )
  400. local size = #self.delay_clear_model_list
  401. if size > 0 then
  402. local len = 3
  403. for i = 1, len do
  404. local class_name = table_remove(self.delay_clear_model_list, 1)
  405. if class_name and not LuaMemManager.KEEP_CACHE_MODEL[class_name] and _G[class_name]
  406. and _G[class_name].Instance then
  407. --执行init函数
  408. local instance = _G[class_name].Instance
  409. instance._class_type.__init(instance)
  410. end
  411. end
  412. else
  413. if self.period_clear_id then
  414. GlobalTimerQuest:CancelQuest(self.period_clear_id)
  415. self.period_clear_id = nil
  416. end
  417. self.is_clearing_model = false
  418. end
  419. end
  420. ]]
  421. function LuaMemManager:__delete()
  422. end