Chi*_*han 8 ruby java string optimization jruby
我们在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
Run Code Online (Sandbox Code Playgroud)
Java中的示例:
String v1 = "a";
String v2 = "a";
System.out.println(v1.hashCode()); # => 97
System.out.println(v2.hashCode()); # => 97
Run Code Online (Sandbox Code Playgroud)
我理解这背后的动机,但JRuby中真的没有这种"神奇"的转换......
从Java背景来看,保存字符串很有诱惑力,但是你不能指望字符串在JRuby中的行为与在Java中的行为相同.首先,它们是完全不同的对象.我甚至会说Ruby String更像是一种Java StringBuilder.
有这么多""实例存在,这当然是一种浪费,但如果你提到的代码是第三方代码,你可以做的事情并不多 - 除非你觉得猴子修补很多.我会尝试识别大多数实例的来源并重构这些 - 但请记住,在保存字符串时有一些"棘手"的部分,例如Hash:
{ 'foo' => 'bar' }
Run Code Online (Sandbox Code Playgroud)
你猜这会产生3个物体,但你错了; 它实际上创造了两个'foo'.因为a String是可变的(除非frozen?)当用作键时它dup是字符串和freezes Hash(并且有充分的理由).
还要记住要"智能地"重构 - 如果你不通过试图在分配的实例上获得便宜而减慢速度,那么就要改变你正在改变的位.
v1 = v2 = v3 = "a"
Run Code Online (Sandbox Code Playgroud)
在 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"
Run Code Online (Sandbox Code Playgroud)
在做一些像实习所有字符串这样激烈的事情之前,我会与其他 tomcat 用户核实这是否是处理这个问题的最佳方法。我不使用 Tomcat 或 JRuby,但我强烈怀疑这不是最好的方法。
编辑如果从“a”构建的每个对象都是同一对象,则修改其中一个对象将修改所有其他字符串。那将是一场副作用噩梦。