5

PythonアプリケーションとTomcatサービス内で実行するサードパーティのJavaライブラリ間のJSONインターフェイスとしてApacheAvroを使用しています。org.apache.avro.ipc.ResponderServletクラスを拡張して、独自のサーブレットを実装することにしました。サーブレットは、コンストラクタでResponderServletスーパークラスをインスタンス化し、init()メソッドとdestroy()メソッドをオーバーライドして、サーブレットで実行するサードパーティライブラリのハウスキーピングを実行するという点で非常に単純です。

ただし、TomcatがWebアプリケーションをアンデプロイすると、ThreadLocal関連のメモリリークを警告する重大なエラーが多数表示されます。

SEVERE: The web application [/hotwire] created a ThreadLocal with key of type [org.apache.avro.Schema$3] (value [org.apache.avro.Schema$3@4464784f]) and a value of type [java.lang.Boolean] (value [true]) but failed to remove it when the web application was stopped. Threads are going to be renewed over time to try and avoid a probable memory leak.
Jan 24, 2013 2:19:36 AM org.apache.catalina.loader.WebappClassLoader checkThreadLocalMapForLeaks
SEVERE: The web application [/hotwire] created a ThreadLocal with key of type [org.apache.avro.generic.GenericDatumReader$1] (value [org.apache.avro.generic.GenericDatumReader$1@2016ad9d]) and a value of type [org.apache.avro.util.WeakIdentityHashMap] (value [org.apache.avro.util.WeakIdentityHashMap@30e02ee0]) but failed to remove it when the web application was stopped. Threads are going to be renewed over time to try and avoid a probable memory leak.

このシナリオでは、Web上のどこにもヘルプが見つからなかったため、おそらくどこかでナイーブなことをしていると思います。それにもかかわらず、私たちはここの誰かが私たちがどこで間違っているのかを教えてくれることを望んでいます。

これがサーブレットの概要です。

public class HotWire extends ResponderServlet{
    public HotWire() throws IOException
    {
              super(new SpecificResponder(Engine.class, new EngineImpl()));
    }

    @Override
        public void init() {
        try {
         super.init();
                 try {
                      init_engine();                
                      } catch (EngineInitException e) {
                      e.printStackTrace();
                      }
            } catch (ServletException e) {
                 e.printStackTrace();
            }
        }

        @Override
        public void destroy() {
            super.destroy();
            shutdown_engine();
        }

        public static class EngineImpl implements EngineInterface  {
            public Boolean create(Parameters message) {
                Boolean status = null;
                try {
                    status = engine.create_object(message);
                } catch (SemanticException | IOException e) {
                    e.printStackTrace();
                }
                return status;
            }

}
4

1 に答える 1

1

同様の問題が発生しています。ここを見ると、静的な ThreadLocal キャッシュがあり、それを削除する方法がありません。

https://github.com/apache/avro/blob/master/lang/java/avro/src/main/java/org/apache/avro/generic/GenericDatumReader.java#L106

  private static final ThreadLocal<Map<Schema, Map<Schema, ResolvingDecoder>>> RESOLVER_CACHE = ThreadLocal
      .withInitial(WeakIdentityHashMap::new);

私の場合、各リクエストには異なるスキーマがあるため、Spring Boot サービスは最終的にメモリ不足になり、停止します。

これもクラスローダー リークの例です: ThreadLocal & Memory Leak

ここで改善のための JIRA リクエストを見ることができます: https://issues.apache.org/jira/browse/AVRO-1595

更新: メモリ リークの問題を回避できました。スレッドを再利用している ExecutorService がありました。ここで、サービスをシャットダウンして、スレッドをファイナライズします。これにより、ThreadLocal メモリを GC できるようになります。

誰かが指摘したように、RESOLVER_CACHE はキャッシュを GC できるようにする WeakIdentityHashMap を使用しますが、これは私には起こりませんでした。

于 2019-04-23T22:21:46.020 に答える