9

私は現在、Tomcat 7(Oracle JDK 7を使用)上のアプリケーションのクラスローダーリークを調査しています。Webアプリケーションクラスローダーへの静的参照を保持する(したがって、再デプロイ/再起動時にクラスローダーが解放されないようにする)1つのクラスはjavax.xml.bind.DatatypeConverter、システムクラスローダーに存在し、そのtheConverterフィールドを介してcom.sun.xml.bind.DatatypeConverterImplSunのjaxbへの静的参照を保持します。 -implパッケージ。

誰かが以前にこの問題を観察したことがありますか?何か提案はありますか(アプリケーションのシャットダウン時にリフレクションを使用して静的フィールドをnullにすることを除く)?

4

2 に答える 2

13

結局のところ、私の依存関係の1つ(com.sun.jersey:jersey-json)が引き込まれcom.sun.xml.bind:jaxb-impl、システムクラスローダー->アプリケーションクラスローダーの参照を担当していました。その依存関係を除外することで問題が解決しました(JDK 7には適切なJAXB実装が付属しており、システムCL内で参照されます。これは問題ありません)。

于 2012-07-06T11:24:47.493 に答える
1

開発中の後続のWebアプリケーションの再デプロイに関するTomcat8の問題の警告:

org.apache.catalina.loader.WebappClassLoaderBase checkThreadLocalMapForLeaks

SEVERE: The web application [rsnetlombard] created a ThreadLocal with key of type
[com.sun.xml.bind.v2.ClassFactory$1] (value [com.sun.xml.bind.v2.ClassFactory$1@79eb7926])
and a value of type [java.util.WeakHashMap]
(value [{class javax.xml.bind.annotation.W3CDomHandler=java.lang.ref.WeakReference@525eec52}])
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.

VisualVM内でヒープダンプを作成して開きます。

VisualVMは、クエリによってOQLタブで破壊されたWebアプリケーションクラスローダーを検索します。

select x from org.apache.catalina.loader.WebappClassLoader x where x.state.name.toString() == "DESTROYED"

[インストール]タブでオブジェクトへのポイントリンクにアクセスすると、[参照セクション]で[最も近いGCルートを検索]を呼び出し、テキスト表現をクリップボードにコピーできます::

this     - value: org.apache.catalina.loader.WebappClassLoader #3
 <- <classLoader>     - class: com.sun.xml.bind.DatatypeConverterImpl, value: org.apache.catalina.loader.WebappClassLoader #3
  <- <class>     - class: com.sun.xml.bind.DatatypeConverterImpl, value: com.sun.xml.bind.DatatypeConverterImpl class DatatypeConverterImpl
   <- theConverter (sticky class)     - class: javax.xml.bind.DatatypeConverter, value: com.sun.xml.bind.DatatypeConverterImpl #1

javax.xml.bind.DatatypeConverterJava SEからのものであり、そのクラスはシステムクラスローダーによってロードされます(したがって、マークされます(sticky class))。ただし、Webアプリケーションのクラスローダーによってロードされたクラスをポイントします。

グーグルで検索com.sun.xml.bind.DatatypeConverterImplすると、このSO投稿につながります。

提供されたソリューションは、パッケージがcom.sun.jersey:jersey-jsonパッケージからJAXBAPI実装を要求すると言いcom.sun.xml.bind:jaxb-implます::

$ mvn dependency:tree
...
[INFO] +- com.sun.jersey:jersey-json:jar:1.8:compile
[INFO] |  +- org.codehaus.jettison:jettison:jar:1.1:compile
[INFO] |  |  \- stax:stax-api:jar:1.0.1:compile
[INFO] |  +- com.sun.xml.bind:jaxb-impl:jar:2.2.3-1:compile
[INFO] |  |  \- javax.xml.bind:jaxb-api:jar:2.2.2:compile
[INFO] |  |     \- javax.xml.stream:stax-api:jar:1.0-2:compile
[INFO] |  +- org.codehaus.jackson:jackson-core-asl:jar:1.7.1:compile
[INFO] |  +- org.codehaus.jackson:jackson-mapper-asl:jar:1.7.1:compile
[INFO] |  +- org.codehaus.jackson:jackson-jaxrs:jar:1.7.1:compile
[INFO] |  \- org.codehaus.jackson:jackson-xc:jar:1.7.1:compile

Java 7には独自のJAXB実装(実際にはJAXB RIcom.sun.xml.bind:jaxb-impl )が付属しているため、 パッケージは必要ありません。pom.xml::の対応する部分に除外を追加します

    <dependency>
        <groupId>com.sun.jersey</groupId>
        <artifactId>jersey-json</artifactId>
        <version>${jersey.version}</version>
        <exclusions>
            <exclusion>
                <groupId>com.sun.xml.bind</groupId>
                <artifactId>jaxb-impl</artifactId>
            </exclusion>
        </exclusions>
    </dependency>

テストでより早く結果に到達するために、Tomcatメモリを減らします::

JAVA_OPTS="-Djava.awt.headless=true -Xmx212m -XX:+UseConcMarkSweepGC -XX:MaxPermSize=66m"

アプリケーションを10回再展開/使用すると、次の場合は何も得られません。

select x from org.apache.catalina.loader.WebappClassLoader x where x.state.name.toString() == "DESTROYED"

再デプロイの下で、「VisualGC」プラグインにPermGenのクリーンアップが表示されます。

以前の開発セットアップで実行するには、次のものが必要です。

JAVA_OPTS="-Djava.awt.headless=true -Xmx512m -XX:+UseConcMarkSweepGC -XX:MaxPermSize=256m"

4〜5回の再デプロイを生き残るために。より大きなPermGenに対するOQLクエリは、いくつかのTomcatを提供WebappClassLoader しますが、インスタンスを調べると、GCへのパスがなく、PermGenがいっぱいになるとクリーンアップされることが示されました。

于 2015-12-19T21:15:40.117 に答える