加入我们,或者,欢迎回来。
您需要 登录 才可以下载或查看,没有帐号?注册会员
x
本帖最后由 taroxd 于 2014-8-2 20:03 编辑
写这个东西的原因,是某游戏制作组表示内存溢出,然后我就帮他们检查了一下。
一检查吓一跳,原来著名的 Yanfly Battle Engine 还有 Fuki 对话框都有未释放 Sprite 或者 Bitmap 的问题!
我想说的,是这些 Ruby 的技巧展现出的威力。
@喵呜喵5 和我说,制作一个游戏不需要超过 F1 手册的 Ruby 知识。
但我觉得,对 Ruby 理解的更深入一点总是好的。
至少,不用这一种【内省】的方式,是很难找出别人写的代码中的 bug 的。
代码中的 def_xxx 可以理解为我的免 alias 补丁(也是元编程!),也可以简单地理解为伪代码,表示在原方法前后补充执行一段代码。
请把下面的脚本当作一个学习脚本的示例,而不是把这个脚本直接拿去用。因为不会脚本的人,你用了也看不懂输出结果。
class Viewport def_before(:dispose) { @__dispose__ = true } def disposed?; @__dispose__; end end need_dispose = [Bitmap, Sprite, Window, Plane, Tilemap, Viewport] callers = {} callers.compare_by_identity not_disposed = [] need_dispose.each do |klass| klass.class_eval do def_after(:initialize) {|*| callers[self] = caller } end end Scene_Base.class_eval do def_after :terminate do need_dispose.each do |klass| ObjectSpace.each_object(klass) do |obj| not_disposed.push(obj) unless obj.disposed? end end end def_after :update do return unless Input.trigger?(:ALT) # 按下ALT键时显示检测结果 puts not_disposed.delete_if(&:disposed?) # 输出所有未释放的对象 puts callers[ not_disposed.shuffle.find do |obj| # 随机找出一个不是 Cache 中生成的,未释放的对象,输出其 caller # 如果不存在,则输出一个空行 callers[obj] && callers[obj].none? {|str| str.start_with?('{0004}') } end ] end end
class Viewport
def_before(:dispose) { @__dispose__ = true }
def disposed?; @__dispose__; end
end
need_dispose = [Bitmap, Sprite, Window, Plane, Tilemap, Viewport]
callers = {}
callers.compare_by_identity
not_disposed = []
need_dispose.each do |klass|
klass.class_eval do
def_after(:initialize) {|*| callers[self] = caller }
end
end
Scene_Base.class_eval do
def_after :terminate do
need_dispose.each do |klass|
ObjectSpace.each_object(klass) do |obj|
not_disposed.push(obj) unless obj.disposed?
end
end
end
def_after :update do
return unless Input.trigger?(:ALT) # 按下ALT键时显示检测结果
puts not_disposed.delete_if(&:disposed?) # 输出所有未释放的对象
puts callers[
not_disposed.shuffle.find do |obj|
# 随机找出一个不是 Cache 中生成的,未释放的对象,输出其 caller
# 如果不存在,则输出一个空行
callers[obj] && callers[obj].none? {|str| str.start_with?('{0004}') }
end
]
end
end
Q: 找到未释放的对象之后,为什么不直接释放该对象,而是追踪该对象的生成呢?
A: 我希望从脚本的根源解决问题,而不是掩盖一个脚本设计者的疏忽。 |