6

Tomcatで実行されているJRubyonRailsで記述された小さなWebアプリケーションを実行しています。別の本番Webアプリケーションと共有されているSpringバックエンドを使用しています。残念ながら、PermGenの問題が発生し続けています。

OS:Ubuntu Linux 2.6.24-24-サーバー#1 SMP x86_64 GNU / Linux Java:1.6.0_21 Tomcat:6.0.28 JRuby:1.5.0 Rails:2.3.7

現在、Google、Yahoo、Baiduによってクロールされているため、サイトの使用率は上がっています。私はJConsoleを使用してTomcatを監視してきましたが、クラスの数が多すぎるという問題が確実に発生しています。tomcatが起動すると、約12,000のクラスがロードされます。8時間後、約75,000のクラスがロードされました。PermGenは同時に100MBから460MBになります。

クラスのアンロードは機能していますが、同じ8時間で約500クラスしかアンロードされませんでした。PermGenが収集されることはないようです。

Tomcat用に次のVMオプションを使用して実行しています。

-Xms2048m -Xmx2048m -XX:MaxPermSize=512m -XX:PermSize=128m \
-XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:ParallelGCThreads=4 \
-XX:+CMSClassUnloadingEnabled -XX:+CMSPermGenSweepingEnabled

明らかに、ある種のリークがあります。問題は、どのようにどこにあるのかということです。誰が、何がこれに責任があるのか​​を追跡する方法について何かアドバイスはありますか?それが私たちの側の本当にばかげた間違いであることを願っていますが、どこから始めればよいのかわかりません。

アドバイスをいただければ幸いです。

編集

着信リクエストごとに1つの新しいクラスが作成されているようです。

編集2

それは間違いなくJRubyに関連しています。JConsoleを使用して、クラスローダーの詳細モードを有効にしました。これがcatalina.outからのサンプルです:

[Loaded anon_class1275113147_895127379 from file:/opt/apache-tomcat-6.0.28/webapps/notes/WEB-INF/lib/jruby-core-1.5.0.jar]
[Loaded anon_class1354333392_895127376 from file:/opt/apache-tomcat-6.0.28/webapps/notes/WEB-INF/lib/jruby-core-1.5.0.jar]
[Loaded anon_class1402528430_895127373 from file:/opt/apache-tomcat-6.0.28/webapps/notes/WEB-INF/lib/jruby-core-1.5.0.jar]

したがって、問題は、これらの追加クラスの作成を担当する当事者をどのように追跡するかということです。

編集3

これが問題かどうかはわかりませんが、どういうわけか、クラスローダーの数が非常に多くなっています。走っjmap -permstat PIDて得た:

class_loader  classes bytes       parent_loader   alive?              type
total = 1320  135748  947431296   N/A             alive=1, dead=1319  N/A

それは少し過剰に思えます。大部分は、、、またはの3種類のクラスローダーのsun.reflect.DelegatingClassLoaderいずれorg.jruby.util.JRubyClassLoaderorg.jruby.util.ClassCache$OneShotClassLoaderです。繰り返しますが、からのサンプル出力jmap -permstat

class_loader            classes bytes      parent_loader           alive?  type
0x00007f71f4e93d58      1       3128       0x00007f71f4d54680      dead    sun/reflect/DelegatingClassLoader@0x00007f72ef9a6dc0
0x00007f721e51e2a0      57103   316038936  0x00007f720431c958      dead    org/jruby/util/JRubyClassLoader@0x00007f72f2fd1158
0x00007f72182f2b10      4       12944      0x00007f721d7f3030      dead    org/jruby/util/JRubyClassLoader@0x00007f72f2fd1158
0x00007f721d7d50d8      9       457520     0x00007f720431c958      dead    org/jruby/util/ClassCache$OneShotClassLoader@0x00007f72f3ce2368
4

4 に答える 4

6

PermGen は、JRuby ベースのアプリケーションでは間違いなく問題です。CMS があまり収集されていないことには驚かない。通常、真のメモリ リークはありませんが、アプリケーションが重くて permgen が難しく、まだ平準化されていません。

いくつかのオプションを提供できます。

  1. permgen をさらに上げて、横ばい点を見つけることができるかどうかを確認します。
  2. アプリケーションをピュア インタープリター モード (-Djruby.compile.mode=OFF) で実行できるかどうかを確認してください。これにより、permgen を埋め尽くすクラスの大部分が取り除かれます。
  3. Rails 2.2 以降のthreadsafe!モードで実行してみてください。単一のランタイムでアプリケーションを実行することは、メモリを大幅に節約するもう 1 つの方法であり、permgen にも当てはまります。

編集: 参考までに、この質問はJRuby のバグであることが判明しました。1.5.2 および 1.6 リリースでは、この特定の問題が修正されるはずです。上記の私のコメントはまだ一般的です。

于 2010-07-16T17:48:44.093 に答える
2

JRuby 1.5.1 を使用した Sinatra Web アプリケーションでも同様の問題がありました。JVM TraceClassLoading オプションは、すべてのリクエストとともにロードされた anon_class* を出力します。

その匿名クラスがロードされた場所を絞り込むためにしばらく時間を費やした後、これはコンソールにトレースステートメントを出力することによって行われ、Java オブジェクトで欠落しているメソッドを呼び出すことが原因であることが最終的に判明しました。

この呼び出しにより、JRuby は欠落しているメソッドを Java オブジェクトに追加しました。そのプロセスで、「anon_class」という名前の後にいくつかのハッシュ値が続く新しいシングルトン JRuby クラスが作成されました。これはクラス型であるため、PermGen にとどまり、GC によって収集されることはありません。

回避策は、不足しているメソッドを呼び出さないようにするか、実装を提供することです。この場合、Java ArrayList オブジェクトのブロックで sort メソッドを呼び出そうとしました。最初に「to_a」メソッドを呼び出して Java ArrayList を JRuby 配列に変換すると、ブロックでソートしても anon_class が作成されません。

したがって、JRudy から Java オブジェクトにアクセスする場所のコードを確認することをお勧めします。

于 2010-07-29T23:17:55.840 に答える
2

この問題と回避策を示す簡単な例を提供するだけです。

require 'java'
include_class java.util.ArrayList

list = ArrayList.new
list << 3
list << 2
list << 1

3.times do
  new_list = list.sort { |a, b| a <=> b}
  #new_list = list.to_a.sort { |a, b| a <=> b}
  puts new_list
end

ファイル名が test_classload.rb であると仮定すると、以下が出力されます。grep anon_class
[JVM_DefineClass からanon_class819349464_307995535をロード]
[JVM_DefineClass からanon_class729155693_307995574をロード]
[JVM_DefineClass からanon_class1690464956_307995577をロード]

コメント行に切り替えると、出力は空です: anon_class がロードされていません。

于 2010-07-30T13:57:55.740 に答える
2

プロファイリング ツールがあり、その使用方法を知っている人がいます。私は彼らの一人ではありません、恐れています。

力ずくのアドバイス:

Tomcat を 8 時間ごとに再起動します。ユーザーから見たダウンタイムの合計は、非常に許容範囲内です。問題が解決しました ;)


編集

いいよ!退屈な解決策

于 2010-07-16T16:26:41.743 に答える