最近、私のWebアプリケーションでこのエラーに遭遇しました:
java.lang.OutOfMemoryError:PermGen space
これは、Tomcat 6およびJDK 1.6で実行される典型的なHibernate / JPA + IceFaces / JSFアプリケーションです。どうやらこれは、アプリケーションを数回再デプロイした後に発生する可能性があります。
何が原因で、それを避けるために何ができますか?どうすれば問題を解決できますか?
最近、私のWebアプリケーションでこのエラーに遭遇しました:
java.lang.OutOfMemoryError:PermGen space
これは、Tomcat 6およびJDK 1.6で実行される典型的なHibernate / JPA + IceFaces / JSFアプリケーションです。どうやらこれは、アプリケーションを数回再デプロイした後に発生する可能性があります。
何が原因で、それを避けるために何ができますか?どうすれば問題を解決できますか?
回答:
解決策は、Tomcatの起動時にこれらのフラグをJVMコマンドラインに追加することでした。
-XX:+CMSClassUnloadingEnabled -XX:+CMSPermGenSweepingEnabled
これを行うには、tomcatサービスをシャットダウンしてから、Tomcat / binディレクトリに移動してtomcat6w.exeを実行します。[Java]タブで、[Javaオプション]ボックスに引数を追加します。「OK」をクリックして、サービスを再起動します。
エラーが発生した場合、指定されたサービスはインストールされたサービスとして存在しないため、実行する必要があります。
tomcat6w //ES//servicename
ここで、servicenameはservices.mscに表示されるサーバーの名前です。
出典:上ORXさんのコメントエリックのアジャイル回答。
あなたはより良い試す-XX:MaxPermSize=128M
のではなく-XX:MaxPermGen=128M
。
このメモリプールの正確な使用法はわかりませんが、JVMにロードされたクラスの数に関係しています。(したがって、tomcatのクラスのアンロードを有効にすると、問題を解決できます。)アプリケーションが実行時にクラスを生成およびコンパイルする場合、デフォルトより大きなメモリプールが必要になる可能性が高くなります。
複数のデプロイ後に発生するアプリサーバーのPermGenエラーは、コンテナが古いアプリのクラスローダーに保持している参照が原因である可能性が高いです。たとえば、カスタムログレベルクラスを使用すると、アプリサーバーのクラスローダーによって参照が保持されます。これらのクラスローダー間リークを検出するには、jmapやjhatなどの最新の(JDK6 +)JVM分析ツールを使用して、アプリで引き続き保持されているクラスを調べ、その使用を再設計または排除します。通常の容疑者は、データベース、ロガー、およびその他の基本フレームワークレベルのライブラリです。
Classloaderリーク:恐ろしい "java.lang.OutOfMemoryError:PermGen space"例外、特にそのフォローアップの投稿を参照してください。
人々が犯す一般的な間違いは、ヒープ領域とpermgen領域が同じであると考えることですが、これはまったく正しくありません。ヒープに多くのスペースが残っている可能性がありますが、permgenでメモリが不足する可能性があります。
PermGenのOutofMemoryの一般的な原因はClassLoaderです。クラスがJVMにロードされると、そのすべてのメタデータはClassloaderとともにPermGen領域に保持され、それらをロードしたClassloaderがガベージコレクションの準備ができるとガベージコレクションされます。場合、クラスローダーはメモリリークを起こし、それによって読み込まれたすべてのクラスがメモリに残り、数回繰り返すとpermGenのメモリ不足を引き起こします。古典的な例は、TomcatのJava.lang.OutOfMemoryError:PermGen Spaceです。
これを解決するには、次の2つの方法があり
ます。1.メモリリークの原因を見つけるか、メモリリークがあるかどうかを確認します。
2. JVMパラメータ-XX:MaxPermSize
とを使用して、PermGenスペースのサイズを増やします-XX:PermSize
。
詳細については、Java のJava.lang.OutOfMemoryErrorの2 Solutionを確認することもできます。
-XX:MaxPermSize and -XX:PermSize
?見つかりませんcatalina.bat
。私のTomcatバージョンは5.5.26
です。
-XX:MaxPermSize=128m
Sun JVM のコマンドラインパラメータを使用します(明らかに、必要なサイズを128に置き換えます)。
試してみ-XX:MaxPermSize=256m
て、それが続く場合は試してください-XX:MaxPermSize=512m
XX:MaxPermSize=1024m
:)
私はeclipse ideを使用しているため、VM引数に追加しました -XX: MaxPermSize = 128m
(どれが最適に機能するか試すことができます)。ほとんどのJVMでは、デフォルトのPermSizeは約64MBであり、プロジェクト内のクラスが多すぎたり、文字列の数が多すぎたりすると、メモリが不足します。
ステップ1:[ サーバー]タブでtomcatサーバーをダブルクリックします
ステップ2:Launch Confを開き-XX: MaxPermSize = 128m
、既存のVM引数の最後に追加します。
複雑なWebアプリケーションのデプロイとアンデプロイの際にも、この問題に頭を悩ませており、説明と解決策を追加したいと思いました。
Apache Tomcatにアプリケーションをデプロイすると、そのアプリケーション用に新しいClassLoaderが作成されます。次に、ClassLoaderを使用して、アプリケーションのすべてのクラスをロードし、アンデプロイ時に、すべてがうまく機能するはずです。ただし、実際にはそれほど単純ではありません。
Webアプリケーションの存続期間中に作成された1つ以上のクラスは、静的な参照を保持します。これは、行のどこかでClassLoaderを参照します。参照はもともと静的であるため、ガベージコレクションによってこの参照がクリーンアップされることはありません。ClassLoaderとそれがロードするすべてのクラスはそのまま残ります。
そして、いくつかの再デプロイの後、OutOfMemoryErrorが発生します。
現在、これはかなり深刻な問題になっています。再デプロイのたびにTomcatを確実に再起動することはできますが、再デプロイされているアプリケーションだけでなく、サーバー全体がダウンします。これは、多くの場合実行不可能です。
代わりに、Apache Tomcat 6.0で機能するソリューションをコードにまとめました。私は他のアプリケーションサーバーでテストしていません。これは他のアプリケーションサーバーで変更しないと機能しない可能性が非常に高いことを強調する必要があります。
また、個人的にはこのコードが嫌いであり、既存のコードを変更して適切なシャットダウンとクリーンアップの方法を使用できる場合は、誰もこれを「クイックフィックス」として使用しないでください。これを使用する必要があるのは、独自の静的参照をクリーンアップする手段を提供しない、コードが依存している外部ライブラリ(私の場合はRADIUSクライアント)がある場合のみです。
とにかく、コードを続けます。これは、サーブレットのdestroyメソッドや(より良いアプローチ)ServletContextListenerのcontextDestroyedメソッドなど、アプリケーションがアンデプロイされる時点で呼び出す必要があります。
//Get a list of all classes loaded by the current webapp classloader
WebappClassLoader classLoader = (WebappClassLoader) getClass().getClassLoader();
Field classLoaderClassesField = null;
Class clazz = WebappClassLoader.class;
while (classLoaderClassesField == null && clazz != null) {
try {
classLoaderClassesField = clazz.getDeclaredField("classes");
} catch (Exception exception) {
//do nothing
}
clazz = clazz.getSuperclass();
}
classLoaderClassesField.setAccessible(true);
List classes = new ArrayList((Vector)classLoaderClassesField.get(classLoader));
for (Object o : classes) {
Class c = (Class)o;
//Make sure you identify only the packages that are holding references to the classloader.
//Allowing this code to clear all static references will result in all sorts
//of horrible things (like java segfaulting).
if (c.getName().startsWith("com.whatever")) {
//Kill any static references within all these classes.
for (Field f : c.getDeclaredFields()) {
if (Modifier.isStatic(f.getModifiers())
&& !Modifier.isFinal(f.getModifiers())
&& !f.getType().isPrimitive()) {
try {
f.setAccessible(true);
f.set(null, null);
} catch (Exception exception) {
//Log the exception
}
}
}
}
}
classes.clear();
の java.lang.OutOfMemoryError: PermGen
スペースのメッセージは、メモリ内のPermanent世代の面積が排出されることを示しています。
Javaアプリケーションは、限られた量のメモリを使用できます。特定のアプリケーションが使用できるメモリの正確な量は、アプリケーションの起動時に指定されます。
Javaメモリは、次の図に示すように、さまざまな領域に分かれています。
メタスペース:新しいメモリ空間が生まれる
JDK 8 HotSpot JVMは、クラスメタデータの表現にネイティブメモリを使用しており、Metaspaceと呼ばれています。Oracle JRockitおよびIBM JVMに似ています。
朗報ですが、これはjava.lang.OutOfMemoryError: PermGen
スペースの問題がなくなり、Java_8_Download以降を使用してこのメモリスペースを調整および監視する必要がなくなるということです。
最初にできることは、永続的な世代のヒープ領域のサイズを大きくすることです。これは、通常の–Xms(set heap size)および–Xmx(set maximum heap size)JVM引数では実行できません。前述のように、永続的な世代のヒープスペースは通常のJavaヒープスペースから完全に分離されており、これらの引数が設定されています。この通常のJavaヒープスペースのスペース。ただし、永続的な生成ヒープのサイズを大きくするために使用できる同様の引数があります(少なくともSun / OpenJDK jvmsを使用)。
-XX:MaxPermSize=128m
デフォルトは64mです。
これを適切に処理する別の方法は、PermGenが不足しないようにクラスをアンロードできるようにすることです。
-XX:+CMSClassUnloadingEnabled -XX:+CMSPermGenSweepingEnabled
そのようなものは過去に私にとって魔法のように働きました。ただし、permgenスイープは、実行するすべてのリクエストまたはそれらのラインに沿った何かに対して追加の2リクエストのようになるため、これらの使用には大きなパフォーマンストレードオフがあります。使用とトレードオフのバランスをとる必要があります。
このエラーの詳細を見つけることができます。
http://faisalbhagat.blogspot.com/2014/09/java-outofmemoryerror-permgen.html
あるいは、permgenをsunのjvmとは異なる方法で処理するJRockitに切り替えることができます。通常、パフォーマンスも向上します。
http://www.oracle.com/technetwork/middleware/jrockit/overview/index.html
java.lang.OutOfMemoryError: There is insufficient native memory
代わりに取得します。
私がここで話している問題がありました、私のシナリオはeclipse-helios + tomcat + jsfで、あなたがやっていたことは単純なアプリケーションをtomcatにデプロイすることです。ここで同じ問題を示していましたが、次のように解決しました。
Eclipseで[ サーバー ]タブに移動し、登録済みのサーバーをダブルクリックします(私の場合はtomcat 7.0)。ファイルサーバーの一般的な登録情報が開きます。「一般情報」セクションで「起動構成を開く」リンクをクリックすると、これらの2つのエントリの最後に追加されたVM引数の「引数」タブでサーバーオプションの実行が開きます。
-XX: MaxPermSize = 512m
-XX: PermSize = 512m
そして準備ができています。
最近の最も簡単な答えは、Java 8を使用することです。
PermGenスペース専用のメモリは予約されなくなり、PermGenメモリは通常のメモリプールと混ざることができます。
-XXPermGen...=...
Java 8が何もしないと文句を言わないようにするには、非標準のJVM起動パラメーターをすべて削除する必要があることに注意してください。
perm genスペースエラーは、コードを実行するためにjvm提供スペースではなく大きなスペースを使用したことが原因で発生します。
UNIXオペレーティングシステムにおけるこの問題の最良の解決策は、bashファイルの一部の構成を変更することです。次の手順で問題を解決します。
gedit .bashrc
端末でコマンドを実行します。
JAVA_OTPS
次の値で変数を作成します。
export JAVA_OPTS="-XX:PermSize=256m -XX:MaxPermSize=512m"
bashファイルを保存します。端末でコマンドexec bashを実行します。サーバーを再起動します。
このアプローチがあなたの問題に役立つことを願っています。8より前のバージョンのJavaを使用すると、この問題が発生することがあります。しかし、Java 8を使用する場合、問題は発生しません。
私は、Hibernateは+のEclipse RCPの組み合わせを持って使用してみました-XX:MaxPermSize=512m
と-XX:PermSize=512m
、それは私のために働いているようです。
私はいくつかの答えを試しましたが、最終的に仕事をしたのはpomのコンパイラプラグインのこの構成だけでした:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<fork>true</fork>
<meminitial>128m</meminitial>
<maxmem>512m</maxmem>
<source>1.6</source>
<target>1.6</target>
<!-- prevent PermGen space out of memory exception -->
<!-- <argLine>-Xmx512m -XX:MaxPermSize=512m</argLine> -->
</configuration>
</plugin>
これがお役に立てば幸いです。
メモリの構成は、アプリの性質によって異なります。
何してるの?
処理されたトランザクションの量はいくらですか?
どのくらいのデータを読み込んでいますか?
等
等
等
おそらく、あなたはあなたのアプリをプロファイリングし、あなたのアプリからいくつかのモジュールをクリーンアップし始めることができます。
どうやらこれは、アプリケーションを数回再デプロイした後に発生する可能性があります
Tomcatにはホットデプロイがありますが、メモリを消費します。ときどきコンテナを再起動してみてください。また、プロダクションモードで実行するために必要なメモリの量を知る必要があります。これは、その研究にとって良い時期のようです。
私はまったく同じ問題に遭遇しましたが、残念ながら、提案された解決策のどれも実際にはうまくいきませんでした。この問題はデプロイメント中には発生せず、ホットデプロイメントも行っていません。
私の場合、問題は、(休止状態を介して)データベースに接続しているときに、Webアプリケーションの実行中の同じ時点で毎回発生しました。
このリンク(これも前述)は、問題を解決するのに十分な内部を提供しました。jdbc-(mysql)-driverをWEB-INFからjre / lib / ext /フォルダーに移動すると問題が解決したようです。新しいJREにアップグレードするとドライバーの再インストールが必要になるため、これは理想的なソリューションではありません。同様の問題を引き起こす可能性のある別の候補はlog4jです。そのため、これも移動することができます。
そのような場合の最初のステップは、GCがPermGenからクラスをアンロードできるかどうかを確認することです。標準のJVMはこの点ではかなり保守的です。クラスは永遠に生きるために生まれています。したがって、ロードされると、コードがそれらを使用していない場合でも、クラスはメモリに残ります。これは、アプリケーションが多くのクラスを動的に作成し、生成されたクラスが長期間必要ない場合に問題になる可能性があります。このような場合、JVMがクラス定義をアンロードできるようにすると便利です。これは、起動スクリプトに構成パラメーターを1つだけ追加することで実現できます。
-XX:+CMSClassUnloadingEnabled
デフォルトではfalseに設定されているため、これを有効にするには、Javaオプションで次のオプションを明示的に設定する必要があります。CMSClassUnloadingEnabledを有効にすると、GCはPermGenもスイープし、使用されなくなったクラスを削除します。このオプションは、UseConcMarkSweepGCも以下のオプションを使用して有効になっている場合にのみ機能することに注意してください。したがって、ParallelGCを実行する場合、または、シリアルGCを禁止する場合は、次のように指定してGCをCMSに設定していることを確認してください。
-XX:+UseConcMarkSweepGC
Tomcatにさらに多くのメモリを割り当てることは適切な解決策ではありません。
正しい解決策は、コンテキストが破棄されて再作成された後にクリーンアップを行うことです(ホットデプロイ)。解決策は、メモリリークを停止することです。
Tomcat / Webappサーバーがドライバー(JDBC)の登録解除に失敗したことを通知している場合は、それらを登録解除します。これにより、メモリリークが停止します。
ServletContextListenerを作成して、web.xmlで構成できます。次にServletContextListenerのサンプルを示します。
import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Enumeration;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import org.apache.log4j.Logger;
import com.mysql.jdbc.AbandonedConnectionCleanupThread;
/**
*
* @author alejandro.tkachuk / calculistik.com
*
*/
public class AppContextListener implements ServletContextListener {
private static final Logger logger = Logger.getLogger(AppContextListener.class);
@Override
public void contextInitialized(ServletContextEvent arg0) {
logger.info("AppContextListener started");
}
@Override
public void contextDestroyed(ServletContextEvent arg0) {
logger.info("AppContextListener destroyed");
// manually unregister the JDBC drivers
Enumeration<Driver> drivers = DriverManager.getDrivers();
while (drivers.hasMoreElements()) {
Driver driver = drivers.nextElement();
try {
DriverManager.deregisterDriver(driver);
logger.info(String.format("Unregistering jdbc driver: %s", driver));
} catch (SQLException e) {
logger.info(String.format("Error unregistering driver %s", driver), e);
}
}
// manually shutdown clean up threads
try {
AbandonedConnectionCleanupThread.shutdown();
logger.info("Shutting down AbandonedConnectionCleanupThread");
} catch (InterruptedException e) {
logger.warn("SEVERE problem shutting down AbandonedConnectionCleanupThread: ", e);
e.printStackTrace();
}
}
}
そして、あなたはあなたのweb.xmlでそれを設定します:
<listener>
<listener-class>
com.calculistik.mediweb.context.AppContextListener
</listener-class>
</listener>
ケースであなたもパラメータを設定した後、EclipseのIDEでこれを取得している
--launcher.XXMaxPermSize
、-XX:MaxPermSize
など、あなたが同じエラーを取得している場合は、まだ、それが最も可能性が高い日食がいくつかによってインストールされていたであろうJREのバグのあるバージョンを使用していることですサードパーティのアプリケーションとデフォルトに設定。これらのバグのあるバージョンはPermSizeパラメータを取得しないため、設定した値に関係なく、引き続きこれらのメモリエラーが発生します。したがって、eclipse.iniに次のパラメーターを追加します。
-vm <path to the right JRE directory>/<name of javaw executable>
また、Eclipseの設定でデフォルトのJREがJavaの正しいバージョンに設定されていることを確認してください。
私にとってうまくいった唯一の方法は、JRockit JVMでした。MyEclipse 8.6を持っています。
JVMのヒープには、実行中のJavaプログラムによって生成されたすべてのオブジェクトが格納されます。Javaはnew
演算子を使用してオブジェクトを作成し、新しいオブジェクトのメモリは実行時にヒープに割り当てられます。ガベージコレクションは、プログラムによって参照されなくなったオブジェクトに含まれるメモリを自動的に解放するメカニズムです。
私は同様の問題を抱えていました。私のものは、JDK 7 + Maven 3.0.2 + Struts 2.0 + Google GUICE依存性注入ベースのプロジェクトです。
mvn clean package
コマンドを実行しようとすると、次のエラーが表示され、「ビルド失敗」が発生しました
org.apache.maven.surefire.util.SurefireReflectionException:java.lang.reflect.InvocationTargetException; ネストされた例外はjava.lang.reflect.InvocationTargetException:null java.lang.reflect.InvocationTargetExceptionです。原因:java.lang.OutOfMemoryError:PermGen space
上記の役立つヒントやテクニックをすべて試しましたが、残念ながらどれもうまくいきませんでした。私のために働いたことは以下のステップバイステップで説明されています:=>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
要素を追加し、次に<argLine>
サブ要素を追加します。次に-Xmx512m -XX:MaxPermSize=256m
示すようにパスを渡します=><configuration>
<argLine>-Xmx512m -XX:MaxPermSize=256m</argLine>
</configuration>
それが役に立てば幸いです、幸せなプログラミング:)