JRuby を 1.5.2 から 1.6.1 にアップグレードするときに興味深い問題に遭遇しました。一握りの行に煮詰めるまで、週末中ずっと忍び寄っていました。getEngineByName が何度も呼び出されると失敗するバグがどこかに導入されたようです。たとえば、次の非常に単純なコードは 1.5.2 では機能しますが、1.6.1 では約 10 ~ 20 回の反復後に失敗します。
ScriptEngineManager factory = new ScriptEngineManager();
for (int i = 0; i < 10000; i++) {
System.out.println(i);
ScriptEngine engine = factory.getEngineByName("jruby");
engine.eval("puts 'hello'");
}
#16 の後の 1.6.1 の結果:
NameError: uninitialized constant #<Class:0x101a41cc7>::ARGV
const_missing at org/jruby/RubyModule.java:2526
Exception in thread "main" java.lang.NullPointerException
at org.jruby.embed.jsr223.JRubyEngine.wrapException(JRubyEngine.java:110)
at org.jruby.embed.jsr223.JRubyEngine.eval(JRubyEngine.java:93)
at org.jruby.embed.jsr223.JRubyEngine.eval(JRubyEngine.java:154)
at JRubyTestFailure.main(JRubyTestFailure.java:16)
この問題を回避するには、getEngineByName をループの外に移動するだけです。
ScriptEngineManager factory = new ScriptEngineManager();
ScriptEngine engine = factory.getEngineByName("jruby");
for (int i = 0; i < 10000; i++) {
System.out.println(i);
engine.eval("puts 'hello'");
}
残念ながら、アーキテクチャ上の理由から、これは私のアプリケーションにとってそれほど簡単ではありません。別の ScriptEngine インスタンスを ThreadLocal に配置する必要がある場合があります。なぜこれが失敗するのか理解できないのは心配です。
この「NameError: uninitialized constant」エラーが発生する理由についてのアイデアはありますか? いいえ、まだソースをチェックアウトしていません...