设为首页收藏本站|繁體中文

Project1

 找回密码
 注册会员
搜索
查看: 47|回复: 0
打印 上一主题 下一主题

[原创发布] [案例分析]字体频繁更新导致的Joiplay非典型内存泄漏

[复制链接]

Lv1.梦旅人

梦石
0
星屑
120
在线时间
9 小时
注册时间
2025-6-8
帖子
3
跳转到指定楼层
1
发表于 前天 11:16 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

加入我们,或者,欢迎回来。

您需要 登录 才可以下载或查看,没有帐号?注册会员

x
一般来说,我们认为RGSS的内存泄漏通常发生在需要主动dispose的资源类型上,
其他的数据类型如果不是刻意为之,很难导致严重的内存泄漏,
但是,由于Joiplay的引擎底层跟RPGMaker PC端并不完全一致,
可能就会导致一些在PC端上没有任何问题的脚本,在Joiplay上出现严重的问题
其中,Joiplay的字体缓存就是重灾区

请看以下这段代码:
RUBY 代码复制
  1. def draw_text(x,y,w)
  2.     return unless @cur_val
  3.     @window.contents.font.name = "VL GOTHIC"
  4.     @window.change_color(@window.system_color)
  5.     @window.draw_text(x, y, 30, @window.line_height, @vocab)
  6.     @window.change_color(@window.normal_color)
  7.     @window.change_color(@window.crisis_color) if @cur_val < @max_val / 4
  8.     xr = x + w
  9.     if w < 96
  10.       @window.draw_text(xr - 40, y, 42, @window.line_height, @cur_val.to_i, 2)
  11.     else
  12.       @window.draw_text(xr - 92, y, 42, @window.line_height, @cur_val.to_i, 2)
  13.       @window.change_color(@window.normal_color)
  14.       @window.draw_text(xr - 52, y, 12, @window.line_height, "/", 2)
  15.       @window.draw_text(xr - 42, y, 42, @window.line_height, @max_val, 2)
  16.     end
  17.     @window.contents.font.name = Font.default_name[0]
  18.   end

这段代码看起来就是很普通的切换显示字体,显示文本,然后把字体切回去
在PC端上,引擎会从内建的字体缓存中切换字体,几乎没有性能开销
但是在Joiplay上,每次执行这段代码,Joiplay都会尝试重新读取字体,
而不幸的是,这段代码被放在了角色状态栏的动画效果中,
只要进行战斗动作就会随着HPMP的动画效果每帧执行,
最终的结果就是平均每回合提升约60MB的内存占用

那么应该怎么解决呢?
唔呣,既然Joiplay没有字体缓存,那么我们就只好自己创建字体缓存了
具体来说,是把每个Font当作缓存来用,不到万不得已不直接修改Font里的内容
例如,在这个案例中,我选择在类里面塞两个Font作为缓存,
需要用的时候直接切换整个font,这样就可以避免对Font内部做修改导致的Joiplay问题
RUBY 代码复制
  1. class Special_Gauge
  2.   @@original_gauge_font = nil
  3.   @@custom_gauge_font = nil
  4.  
  5.   attr_accessor :cur_val
  6.   def initialize(x,y,w,r,c1,c2,window,height = SPECIAL_GAUGES::DEFAULT_HEIGHT)
  7.     @x = x
  8.     @y = y
  9.     @width = w
  10.     @cur_rate = r
  11.     @max_rate = r
  12.     @color1 = c1
  13.     @color2 = c2
  14.     @window = window
  15.     @speed = 0
  16.     @speed_rate = 0
  17.     @height = height
  18.     @fall_sprites = []
  19.  
  20.     # 修复:初始化字体缓存
  21.     if @@custom_gauge_font.nil?
  22.       @@original_gauge_font = @window.contents.font.deep_copy # 其实就是新建了一个字体然后把所有属性搬过去
  23.       @@custom_gauge_font = @window.contents.font.deep_copy(false) # 少搬一个名字,避免又主动读取字体
  24.       @@custom_gauge_font.name = SPECIAL_GAUGES::CUSTOM_FONT_NAME
  25.     end
  26.  
  27.     refresh
  28.   end
  29.   def draw_text(x,y,w)
  30.     return unless @cur_val
  31.     # 修复:使用字体缓存切换字体而不是名字
  32.     @window.contents.font = @@custom_gauge_font
  33.     @window.change_color(@window.system_color)
  34.     @window.draw_text(x, y, 30, @window.line_height, @vocab)
  35.     @window.change_color(@window.normal_color)
  36.     @window.change_color(@window.crisis_color) if @cur_val < @max_val / 4
  37.     xr = x + w
  38.     if w < 96
  39.       @window.draw_text(xr - 40, y, 42, @window.line_height, @cur_val.to_i, 2)
  40.     else
  41.       @window.draw_text(xr - 92, y, 42, @window.line_height, @cur_val.to_i, 2)
  42.       @window.change_color(@window.normal_color)
  43.       @window.draw_text(xr - 52, y, 12, @window.line_height, "/", 2)
  44.       @window.draw_text(xr - 42, y, 42, @window.line_height, @max_val, 2)
  45.     end
  46.     @window.contents.font = @@original_gauge_font
  47.   end

另外,Joiplay上经常出现的字体透明度错误的问题,也是因为字体缓存没有及时刷新导致的
但是这个问题我还没有研究透彻,也没有找到主动刷新缓存的方案
如果有大佬知道,还请指点一下

您需要登录后才可以回帖 登录 | 注册会员

本版积分规则

拿上你的纸笔,建造一个属于你的梦想世界,加入吧。
 注册会员
找回密码

站长信箱:[email protected]|手机版|小黑屋|无图版|Project1游戏制作

GMT+8, 2025-7-25 23:06

Powered by Discuz! X3.1

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表