8

我们有一个在 tomcat 下运行的 java/jruby webapp,我一直在分析应用程序在运行时使用的对象数量和内存使用情况。启动后我注意到“org.jruby.RubyString”类有1,118,000个字符串“”实例,仅空字符串使用的堆内存总量为65mb,这对我来说很荒谬,因为它是15%的内存由 webapp 使用。空字符串只是存在此问题的许多字符串值的一个示例,如果我可以实习我计算出的所有 jruby 字符串,我可以节省大约 130mb。

我知道在Java中,每次创建字符串值时,它都会检查该值是否已存在于字符串池中,如果存在则重用它。我想知道 Jruby 中是否有具有相同优化的选项?如果是这样,我该如何启用它?

Jruby 中的示例:

v1 = "a"
v2 = "a"
puts v1.object_id # => 3352
puts v2.object_id # => 3354

Java 中的示例:

String v1 = "a";
String v2 = "a";

System.out.println(v1.hashCode()); # => 97
System.out.println(v2.hashCode()); # => 97
4

4 回答 4

5

我理解这背后的动机,但在 JRuby 中真的没有这样的“神奇”开关......

从 Java 的背景来看,保存字符串感觉很诱人,但是您不能期望字符串在 JRuby 中的行为方式与它们在 Java 中的行为方式相同。首先,它们是完全不同的对象。我什至会说 RubyString更像是 Java StringBuilder

有这么多""实例肯定是一种浪费,但如果你提到的代码是第三方代码,那么你无能为力 - 除非你觉得猴子修补了很多。我会尝试识别大多数实例的来源并重构它们 - 但请记住在保存字符串时有一些“棘手”的部分,例如Hash

{ 'foo' => 'bar' }

你会猜这会创建 3 个对象,但你错了;它实际上创建了两个'foo'. 由于 aString是可变的(除非frozen?),它dup是字符串,而freezes 用作Hash键时(这是有充分理由的)。

还要记住“智能地”重构 - 如果您不通过尝试降低分配的实例成本来减慢速度,则可以分析您正在更改的位。

于 2012-05-29T12:41:21.670 回答
2
v1 = v2 = v3 = "a"

只会在 Ruby 中创建一个对象,而不是三个。

v1 = v2 = v3 = "a" # => "a"
v1.object_id # => 10530560
v2.object_id # => 10530560
v1 << "ll the same" # => "all the same"
v2 # "all the same"

在做像实习所有字符串这样激烈的事情之前,我会与其他 tomcat 用户核实这是否是处理这个问题的最佳方法。我不使用 Tomcat 或 JRuby,但我强烈怀疑这不是最好的方法。

编辑如果从“a”构建的每个对象都是同一个对象,那么修改其中一个将修改所有其他字符串。那将是一个副作用的噩梦。

于 2012-05-27T23:21:02.080 回答
1

在 JRuby 中实习 String 的唯一方法是调用to_symor intern(它们相互别名),从而使它们成为符号 - 正如您所提到的,这对第三方 gem 没有多大帮助。据我所知,没有任何其他方式。

这与 MRI 行为一致:

sebastien@greystones:~$ rvm ruby-1.9.3-p0
sebastien@greystones:~$ irb
1.9.3p0 :001 > a = "Hello World" 
 => "Hello World" 
1.9.3p0 :002 > b = "Hello World"
 => "Hello World" 
1.9.3p0 :003 > a.object_id
 => 20126420 
1.9.3p0 :004 > b.object_id
 => 19289920 
于 2012-05-28T06:44:23.453 回答
0

这现在是 JRuby 中的默认行为。从 9.1 版开始,所有冻结的字符串文字(例如'hello'.freeze)都返回相同的实例,用作哈希键的文字字符串(例如stuff['thing'])和其他一些情况也是如此。请参阅JRuby 问题 #3491

如果您想积极冻结所有字符串文字,您可以同时运行 JRuby (9.1+) 和 Ruby (2.3+) with --enable-frozen-string-literal,但要做好准备,因为大多数 gem 假定字符串是可变的。

于 2017-06-19T18:57:40.723 回答