实时应用程序中的 JRuby、大型数组和性能问题
我正在开发一个实时游戏应用程序。其中大部分是用 Java 编写的,但最近我决定尝试将一些初始化过程移至 JRuby 脚本中,以便最大限度地方便玩家修改世界的生成方式。
首先,我决定将地图生成转移到 JRuby 脚本中。目前,这可以归结为以下 Java 代码:
ScriptingContainer container = new ScriptingContainer();
container.put("$data", dataPackage);
container.runScriptlet(PathType.RELATIVE, scriptName);
dataPackage = (BlockMapGenerationDataPackage)container.get("$data");
数据包包含 Java 程序生成最终地形并渲染它所需的所有信息,并且还包含 Ruby 脚本能够生成所需的数据。制作各种地图。特别是,它包含一个相当大的数组(当前为 1000 x 1000 x 15)。为了测试 Ruby 脚本是否正常工作,我去掉了整个地图生成算法,并进行了以下极其简单的测试:
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 地图的旧笔记本电脑上以每秒数百帧的速度以非常高的分辨率流畅运行。然而,当 Java 生成代码被上述 JRuby 脚本替换时,该程序似乎遇到了一些内存消耗问题:帧速率下降了约 30-40 fps,并且程序在令人印象深刻的一致情况下冻结了十分之一秒。大约每三秒一次的周期性频率。分析和各种测试表明,唯一可能的罪魁祸首是 Ruby 脚本。
此外,如果地图的尺寸大幅减小,比如缩小到 100 x 100 x 15,那么这些问题或多或少就会消失。
我尝试过各种方法,例如在 Java 代码之后添加 container.terminate();
或 container.clear();
来执行脚本,但我真的不这样做了解问题的根源或如何解决它。如果有人能解释这里出了什么问题以及是否可以解决这个问题,我将不胜感激!
I'm working on a real-time game application. Most of it is written in Java, but recently I decided to experiment with moving some of the initialization procedures into JRuby scripts in order to maximize the ease for the player to modify how the world is generated.
As a start, I decided to move the map generation into a JRuby script. At present, this boils down to the following Java code:
ScriptingContainer container = new ScriptingContainer();
container.put("$data", dataPackage);
container.runScriptlet(PathType.RELATIVE, scriptName);
dataPackage = (BlockMapGenerationDataPackage)container.get("$data");
The data package contains all the information necessary for the Java program to produce the final terrain and render it, and it also contains the necessary data in order for the Ruby script to be able to craft all manner of maps. In particular, it contains a rather large array (currently 1000 x 1000 x 15). To test whether the Ruby script was working, I've stripped out the entire map generation algorithm and put in the following extremely simple test:
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
This is executed only once upon initialization. Now when this was all implemented in Java, with far more memory intensive generation algorithms, there were no performance or memory issues of any kind. The game ran smoothly at hundreds of frames per second at very high resolutions on an old laptop with a 1000 x 1000 x 15 map. However, when the Java generation code is replaced by the above JRuby script, the program appears to suffer some memory consumption issues: the frame rate drops by about 30-40 fps and the program freezes for maybe a 10th of a second at an impressively consistent periodic rate of about once every three seconds. Profiling and various tests reveal that the only possible culprit is the Ruby script.
Moreover, if the size of the map is drastically reduced, say to 100 x 100 x 15, then these issues more or less disappear.
I've tried various things like adding container.terminate();
or container.clear();
after the Java code to execute the script, but I really don't understand the source of the issue or how to fix it. I'd greatly appreciate if someone could explain what's going wrong here and whether or not this can be fixed!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
最好将地图创建例程作为一个单独的应用程序来链接到 java 应用程序。
我很确定 JRuby 中数组的内存布局会有所不同,这可能会导致您的问题 - 地图对象本身可能是使用不同的内存布局创建的,无论何时访问它,都需要进行一些持续的 JRuby 交互,或者它可能像创建整数而不是整数一样简单,并且由于自动装箱而您没有注意到它(再次,TOTAL猜测,因为我看不到数据类型)
It might be best to make the map creation routine a separate app altogether that chains to the java app.
I'm pretty sure that the memory layout of arrays in JRuby is going to be different and that could be causing your problems--The map object itself may be created with a different memory layout that is requiring some ongoing JRuby interaction whenever it is accessed, or it could be something as simple as creating Integers instead of ints and you aren't noticing it because of autoboxing (Again, TOTAL guess since I can't see data types)
您至少应该尝试一下下标的顺序:[i][j][0] 与 [0][i][j] 和 [0][j][i] 相比。
You should at least experiment with the order of the subscripts: [i][j][0] compared to [0][i][j] and [0][j][i].