我正在开发一个实时游戏应用程序。其中大部分是用 Java 编写的,但最近我决定尝试将一些初始化过程移至 JRuby 脚本中,以便最大限度地方便玩家修改世界的生成方式。
首先,我决定将 map 生成转移到 JRuby 脚本中。目前,这可以归结为以下 Java 代码:
ScriptingContainer container = new ScriptingContainer();
container.put("$data", dataPackage);
container.runScriptlet(PathType.RELATIVE, scriptName);
dataPackage = (BlockMapGenerationDataPackage)container.get("$data");
数据包包含 Java 程序生成最终地形并渲染它所需的所有信息,还包含 Ruby 脚本能够制作各种 map 所需的数据。特别是,它包含一个相当大的数组(当前为 1000 x 1000 x 15)。为了测试 Ruby 脚本是否正常工作,我剥离了整个 map 生成算法并进行了以下极其简单的测试:
require 'java'
Dir["../../dist/\*.jar"].each { |jar| require jar }
for i in (0...$data.getWidth())
for j in (0...$data.getDepth())
$data.blocks[i][j][0] = Java::BlockMap::BlockType::GRASS
end
end
这仅在初始化时执行一次。现在,当这一切都用 Java 实现时,使用更多的内存密集型生成算法,就不存在任何类型的性能或内存问题。该游戏在具有 1000 x 1000 x 15 map 的旧笔记本电脑上以每秒数百帧的速度以非常高的分辨率流畅运行。然而,当 Java 生成代码被上述 JRuby 脚本替换时,该程序似乎遇到了一些内存消耗问题:帧速率下降了约 30-40 fps,并且程序在令人印象深刻的一致情况下卡住了十分之一秒。大约每三秒一次的周期性频率。分析和各种测试表明,唯一可能的罪魁祸首是 Ruby 脚本。
此外,如果 map 的尺寸大幅减小,例如缩小到 100 x 100 x 15,那么这些问题或多或少就会消失。
我尝试过各种方法,例如在 Java 代码之后添加 container.terminate();
或 container.clear();
来执行脚本,但我真的不明白问题的根源或如何解决它。如果有人能解释这里出了什么问题以及是否可以解决这个问题,我将不胜感激!
最佳答案
最好将 map 创建例程制作为一个单独的应用程序,链接到 java 应用程序。
我很确定 JRuby 中数组的内存布局会有所不同,这可能会导致您的问题 - map 对象本身可能是使用不同的内存布局创建的,无论何时都需要一些持续的 JRuby 交互它被访问,或者它可能像创建整数而不是整数一样简单,并且由于自动装箱而您没有注意到它(再次,总猜测,因为我看不到数据类型)
关于java - 实时应用程序中的 JRuby、大型数组和性能问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5957120/