Java 如何分析OutOfMemory GWT错误并自定义堆?

Java 如何分析OutOfMemory GWT错误并自定义堆?,java,gwt,garbage-collection,heap-dump,permgen,Java,Gwt,Garbage Collection,Heap Dump,Permgen,我在一个旧的Java1.6应用程序上工作,它使用GWT2.4.0 从几个星期以来,它开始显示出很多OutOfMemory错误,我不知道为什么。。。 我不能在这个老应用上做很多修改,我不能迁移到JDK1.8,也不能迁移到更新的GWT版本,风险太大了 stacktrace示例: 2021-01-27 09:40:39,937 ERROR [org.apache.catalina.core.ContainerBase.[jboss.web].[localhost].[/borneIntranet]]

我在一个旧的Java1.6应用程序上工作,它使用GWT2.4.0 从几个星期以来,它开始显示出很多OutOfMemory错误,我不知道为什么。。。 我不能在这个老应用上做很多修改,我不能迁移到JDK1.8,也不能迁移到更新的GWT版本,风险太大了

stacktrace示例:

2021-01-27 09:40:39,937 ERROR [org.apache.catalina.core.ContainerBase.[jboss.web].[localhost].[/borneIntranet]] Exception while dispatching incoming RPC call
java.lang.OutOfMemoryError: Java heap space
        at java.util.Arrays.copyOf(Arrays.java:2734)
        at java.util.ArrayList.ensureCapacity(ArrayList.java:167)
        at java.util.ArrayList.add(ArrayList.java:351)
        at com.google.gwt.user.server.rpc.impl.ServerSerializationStreamWriter.append(ServerSerializationStreamWriter.java:583)
        at com.google.gwt.user.client.rpc.impl.AbstractSerializationStreamWriter.writeInt(AbstractSerializationStreamWriter.java:100)
        at com.google.gwt.user.client.rpc.impl.AbstractSerializationStreamWriter.writeString(AbstractSerializationStreamWriter.java:134)
        at com.google.gwt.user.server.rpc.impl.ServerSerializationStreamWriter$ValueWriter$10.write(ServerSerializationStreamWriter.java:165)
        at com.google.gwt.user.server.rpc.impl.ServerSerializationStreamWriter.serializeValue(ServerSerializationStreamWriter.java:536)
        at com.google.gwt.user.server.rpc.impl.ServerSerializationStreamWriter.serializeClass(ServerSerializationStreamWriter.java:709)
        at com.google.gwt.user.server.rpc.impl.ServerSerializationStreamWriter.serializeImpl(ServerSerializationStreamWriter.java:748)
        at com.google.gwt.user.server.rpc.impl.ServerSerializationStreamWriter.serialize(ServerSerializationStreamWriter.java:621)
        at com.google.gwt.user.client.rpc.impl.AbstractSerializationStreamWriter.writeObject(AbstractSerializationStreamWriter.java:126)
        at com.google.gwt.user.client.rpc.core.java.util.Collection_CustomFieldSerializerBase.serialize(Collection_CustomFieldSerializerBase.java:44)
        at com.google.gwt.user.client.rpc.core.java.util.ArrayList_CustomFieldSerializer.serialize(ArrayList_CustomFieldSerializer.java:39)
        at com.google.gwt.user.client.rpc.core.java.util.ArrayList_CustomFieldSerializer.serializeInstance(ArrayList_CustomFieldSerializer.java:51)
        at com.google.gwt.user.client.rpc.core.java.util.ArrayList_CustomFieldSerializer.serializeInstance(ArrayList_CustomFieldSerializer.java:28)
        at com.google.gwt.user.server.rpc.impl.ServerSerializationStreamWriter.serializeImpl(ServerSerializationStreamWriter.java:740)
        at com.google.gwt.user.server.rpc.impl.ServerSerializationStreamWriter.serialize(ServerSerializationStreamWriter.java:621)
        at com.google.gwt.user.client.rpc.impl.AbstractSerializationStreamWriter.writeObject(AbstractSerializationStreamWriter.java:126)
        at com.google.gwt.user.server.rpc.impl.ServerSerializationStreamWriter$ValueWriter$8.write(ServerSerializationStreamWriter.java:153)
        at com.google.gwt.user.server.rpc.impl.ServerSerializationStreamWriter.serializeValue(ServerSerializationStreamWriter.java:539)
        at com.google.gwt.user.server.rpc.impl.ServerSerializationStreamWriter.serializeClass(ServerSerializationStreamWriter.java:709)
        at com.google.gwt.user.server.rpc.impl.ServerSerializationStreamWriter.serializeImpl(ServerSerializationStreamWriter.java:748)
        at com.google.gwt.user.server.rpc.impl.ServerSerializationStreamWriter.serialize(ServerSerializationStreamWriter.java:621)
        at com.google.gwt.user.client.rpc.impl.AbstractSerializationStreamWriter.writeObject(AbstractSerializationStreamWriter.java:126)
        at com.google.gwt.user.server.rpc.impl.ServerSerializationStreamWriter$ValueWriter$8.write(ServerSerializationStreamWriter.java:153)
        at com.google.gwt.user.server.rpc.impl.ServerSerializationStreamWriter.serializeValue(ServerSerializationStreamWriter.java:539)
        at com.google.gwt.user.server.rpc.impl.ServerSerializationStreamWriter.serializeClass(ServerSerializationStreamWriter.java:709)
        at com.google.gwt.user.server.rpc.impl.ServerSerializationStreamWriter.serializeImpl(ServerSerializationStreamWriter.java:748)
        at com.google.gwt.user.server.rpc.impl.ServerSerializationStreamWriter.serialize(ServerSerializationStreamWriter.java:621)
        at com.google.gwt.user.client.rpc.impl.AbstractSerializationStreamWriter.writeObject(AbstractSerializationStreamWriter.java:126)
        at com.google.gwt.user.client.rpc.core.java.util.Collection_CustomFieldSerializerBase.serialize(Collection_CustomFieldSerializerBase.java:44)
2021-01-27 09:40:41,594 ERROR [STDERR] 8312399 [scheduler_QuartzSchedulerThread] ERROR org.quartz.core.ErrorLogger - An error occurred while scanning for the next triggers to fire.
2021-01-27 09:40:42,206 ERROR [STDERR] org.quartz.JobPersistenceException: Failed to obtain DB connection from data source 'springNonTxDataSource.scheduler': java.sql.SQLException: Exception d'E/S: Connection reset [See nested exception:$
2021-01-27 09:40:42,208 ERROR [STDERR]  at org.quartz.impl.jdbcjobstore.JobStoreCMT.getNonManagedTXConnection(JobStoreCMT.java:168)
2021-01-27 09:40:42,208 ERROR [STDERR]  at org.quartz.impl.jdbcjobstore.JobStoreSupport.executeInNonManagedTXLock(JobStoreSupport.java:3784)
2021-01-27 09:40:42,208 ERROR [STDERR]  at org.quartz.impl.jdbcjobstore.JobStoreSupport.acquireNextTriggers(JobStoreSupport.java:2756)
2021-01-27 09:40:42,208 ERROR [STDERR]  at org.quartz.core.QuartzSchedulerThread.run(QuartzSchedulerThread.java:272)
2021-01-27 09:40:42,208 ERROR [STDERR] Caused by: java.sql.SQLException: Exception d'E/S: Connection reset
2021-01-27 09:40:42,208 ERROR [STDERR]  at oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java:111)
2021-01-27 09:40:42,208 ERROR [STDERR]  at oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java:145)
2021-01-27 09:40:42,209 ERROR [STDERR]  at oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java:254)
2021-01-27 09:40:42,209 ERROR [STDERR]  at oracle.jdbc.driver.T4CConnection.logon(T4CConnection.java:386)
2021-01-27 09:40:42,209 ERROR [STDERR]  at oracle.jdbc.driver.PhysicalConnection.<init>(PhysicalConnection.java:413)
2021-01-27 09:40:42,209 ERROR [STDERR]  at oracle.jdbc.driver.T4CConnection.<init>(T4CConnection.java:164)
2021-01-27 09:40:42,209 ERROR [STDERR]  at oracle.jdbc.driver.T4CDriverExtension.getConnection(T4CDriverExtension.java:34)
2021-01-27 09:40:42,209 ERROR [STDERR]  at oracle.jdbc.driver.OracleDriver.connect(OracleDriver.java:752)
2021-01-27 09:40:42,209 ERROR [STDERR]  at org.apache.commons.dbcp.DriverConnectionFactory.createConnection(DriverConnectionFactory.java:38)
2021-01-27 09:40:42,209 ERROR [STDERR]  at org.apache.commons.dbcp.PoolableConnectionFactory.makeObject(PoolableConnectionFactory.java:582)
2021-01-27 09:40:42,209 ERROR [STDERR]  at org.apache.commons.pool.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:1188)
2021-01-27 09:40:42,209 ERROR [STDERR]  at org.apache.commons.dbcp.PoolingDataSource.getConnection(PoolingDataSource.java:106)
2021-01-27 09:40:42,209 ERROR [STDERR]  at org.apache.commons.dbcp.BasicDataSource.getConnection(BasicDataSource.java:1044)
2021-01-27 09:40:42,209 ERROR [STDERR]  at org.springframework.scheduling.quartz.LocalDataSourceJobStore$2.getConnection(LocalDataSourceJobStore.java:134)
2021-01-27 09:40:42,209 ERROR [STDERR]  at org.quartz.utils.DBConnectionManager.getConnection(DBConnectionManager.java:108)
2021-01-27 09:40:42,209 ERROR [STDERR]  at org.quartz.impl.jdbcjobstore.JobStoreCMT.getNonManagedTXConnection(JobStoreCMT.java:165)
2021-01-27 09:40:42,209 ERROR [STDERR]  ... 3 more
我不知道怎么处理。 我也没有太多的应用程序日志,所以我不知道用户真正在做什么,比如显示一个使用大量数据的GWT屏幕,或者其他什么

编辑:

下面是一些gc日志文件,每个文件在一天内生成,直到应用程序因OOM崩溃


你在那里得到了一个漂亮的拼图:-)

我有一些建议供您尝试,因为我认为您是唯一可以复制此内容的人(如果您是唯一拥有代码和代码所操作的数据的人):

  • 我不使用JMXbean,而是使用GC日志记录,因为信息是实时的,直接来自垃圾收集器,请参阅:获取设置和分析。例如:
    -XX:+PrintGCDetails-XX:+PrintGCDateStamps-Xloggc:
  • 尝试增加-Xmx(而不是MaxPermSize)来解决这个问题(在某些情况下,这只会在64位实例上成功,这可能需要额外的内存,使用压缩的oops来避免:),但要清楚java必须使用swap,不要忘了java还需要每个线程堆栈和本机代码的内存,在Java堆的顶部
  • 您可以将Java调试器(例如Eclipse)连接到端口8787,并创建一个异常断点,用于捕获Java.lang.OutOfMemoryError并检查堆栈中的相关值,以查找大型数据集或循环引用。警告:使用调试器断点运行Java可能会降低应用程序的速度,因此对于生产环境来说这可能不是一个好主意,但另一方面,进行堆转储也不利于应用程序的响应时间
  • 您可以从-XX:+heapdumponotofmemoryError(j)visualvm中加载heapdump进行分析,应该比jhat更容易,但这也可能有效)。只有使用HeapDumpOnOutOfMemoryError进行的转储包含到OOMError点的所有信息。不要在互联网上共享heapdump,每个字节的私人信息(个人数据、密码,可能是来自类的字节码)都将成为公共信息 最后,查询的跟踪(JDBC、网络、statspack)可能也会有所帮助,但可能不值得这么麻烦,因为它可能包含太多信息,无法轻松分析

  • 如果您需要更多帮助,请尝试将GC日志记录和启动时的输出:
    -XX:+PrintFlagsFinal
    添加到此帖子。

    存在一些数据库异常,看起来肯定有人正在从中读取大量数据。Thx,但我无法对数据库生成AWR报告(没有快照),数据库服务器的JMX统计数据在内存不足时是正常的……它试图分配内存,但不能,这就是它抛出OOME的原因。堆当前使用率为25%意味着什么也没有。我的猜测是,正如Eugene所说,有一大块数据正在序列化,没有足够的堆空间。谢谢。当OOME发生时,我有一个自动重启,在这种情况下有必要吗?因为它使用25%,所以如果分配不能发生,它就会被阻止,应用程序的其余部分可以继续使用吗?如何搜索“大块”数据?我可以记录每个sql请求(hibernate show_sql),但它会淹没日志,并降低生产速度……不,应用程序无法继续运行。我不知道有什么方法可以取消对内存的请求。虽然您可以捕获错误并继续操作,但这是不可取的。你有数据库方面的日志吗?非常感谢你的回答。我已经添加了几周的GC日志了。我将添加崩溃前生成的GC日志示例。我添加了文件;)分析:
    gc-*-2021-04-11-Crash_10h29.log
    显示(据推测)内存使用量突然增加(参见a&P图):尝试使用visualvm/jvisualvm分析heapdump,如果计算保留大小,请注意:我禁用自动堆转储,因为它们占用了太多磁盘大小。每次我分析它们时,让记忆饱和的对象是字符串、字符。它们与我数据库中的数据相匹配,但难点在于理解为什么内存中突然出现了这么多这样的数据。分析代码没有帮助,到处都有太多的复杂性。我需要确定启动了哪个gwt屏幕或操作,但我不想到处添加log.debug并在生产中启用它…
    /opt/jdk/bin/java -Dprogram.name=run.sh -server -Xms2560m -Xmx2560m -XX:MaxPermSize=768M 
    -Djava.awt.headless=true -Xdebug -Xrunjdwp:transport=dt_socket,address=8787,server=y,suspend=n 
    -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=9999 
    -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false 
    -XX:+UseConcMarkSweepGC -XX:+CMSClassUnloadingEnabled -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp/
    -Djava.net.preferIPv4Stack=true ...