RPG Maker VX的Cache模块的几个小不足

Cache在RMVX中主要负责储存读取过的Bitmap,源码的注释如下

# ■ Cache
#------------------------------------------------------------------------------
#  本模组载入所有图像,建立并保存Bitmap物件。为加快载入速度并节省内存,
#  本模组将以建立的bitmap物件保存在内部哈希表中,使得程序在需求已存在
#  的图像时能快速读取bitmap物件。

Cache模块的重要度自不用说。

如果没有这个模块将bitmap物件保存到哈希表的话,我们不得不对自己生成的每一个bitmap手动dispose,否则程序很会快的吃掉所有内存崩溃。

Cache中最关键的方法如下

  #--------------------------------------------------------------------------
  # * 载入图档
  #--------------------------------------------------------------------------
  def self.load_bitmap(folder_name, filename, hue = 0)
    @cache = {} if @cache == nil
    path = folder_name + filename
    if not @cache.include?(path) or @cache[path].disposed?
      if filename.empty?
        @cache[path] = Bitmap.new(32, 32)
      else
        @cache[path] = Bitmap.new(path)
      end
    end
    if hue == 0
      return @cache[path]
    else
      key = [path, hue]
      if not @cache.include?(key) or @cache[key].disposed?
        @cache[key] = @cache[path].clone
        @cache[key].hue_change(hue)
      end
      return @cache[key]
    end
  end

该方法的主要目的是根据要读取的folder_name和filename拼凑出path,之后把path当做key检查内部哈希表是否已经保存过此bitmap物件

如果已有则返回此物件,否则生成此物件后将其保存进哈希表并返回。

一眼看过去没什么问题,但是有一点小的不足。

假设我们用如下方式调用了两次这个方法

bitmap1 = Cache.load_bitmap("Graphics/picture/", "aaa")
bitmap2 = Cache.load_bitmap("Graphics/picture/", "AAA")

显然,aaa和AAA指的是同一文件,但是两次读取的path并不相同,根本原因就是filename一个是大写一个是小写,从而导致path的不同。

这样的话,Cache会在内部哈希表中保存两个其实一模一样的bitmap物件,如果你的这张图片不巧在1M左右,这样就会浪费掉大量内存。

虽然我们可以强制自己在调用时的全部用小写输入,但难免疏忽,所以我们可以简单处理一下path,将其全部转为大写或者小写即可。

另外,也许由于年代问题,rmvx当时还是直接使用String进行hash的,我们知道Symbol可以节约内存并加快读取速度,所以我们可以把其转为Symbol再哈希。

最后的load_bitmap方法如下

  def self.load_bitmap(folder_name, filename, hue = 0)
    @cache = {} if @cache == nil
    path = (folder_name + filename).downcase
    sym = path.to_sym
    if not @cache.include?(sym) or @cache[sym].disposed?
      if filename.empty?
        @cache[sym] = Bitmap.new(32, 32)
      else
        @cache[sym] = Bitmap.new(path)
      end
    end
    if hue == 0
      return @cache[sym]
    else
      key = [sym, hue]
      if not @cache.include?(key) or @cache[key].disposed?
        @cache[key] = @cache[sym].clone
        @cache[key].hue_change(hue)
      end
      return @cache[key]
    end
  end
原文地址:https://www.cnblogs.com/deadblue/p/2827935.html