分析内存问题

了解如何识别Java应用程序内存问题的原因。 您可以自动手动生成栈转储和栈直方图,以识别原因。

描述 description

环境

Experience Manager

问题/症状

JAVA应用程序运行速度较慢并最终耗尽内存,或者您在日志或控制台输出OutOfMemoryError: Java heap spaceOutOfMemoryError: gc overhead limit exceeded中看到错误。

解决方法 resolution

原因
此类问题可能有很多原因。

一个可能的原因是Java应用程序,在我们的例子中,CRX / CQ是从命令行启动的,默认栈内存设置为Java。 这意味着 jvm 参数 -Xmx 未指定。 CRX 或 CQ 至少需要分配 256 MB 的堆才能运行。 如果这是问题所在,则从命令行开始,请确保设置了堆内存设置。 示例:

java -Xmx512m -jar *.jar

如果不是这种情况,那么您的应用程序可能会保留太多对象而没有为垃圾收集释放它们。这称为内存泄漏,请参阅此处了解更多信息。请参阅下面有关如何分析Java应用程序中的内存问题的部分。
创建栈转储:

自动生成栈转储

要在内存不足时自动创建栈转储,可以添加jvm参数-XX:+HeapDumpOnOutOfMemoryError以在应用程序抛出OutOfMemoryError时自动生成栈转储。 例如,

java -Xmx256m -XX:+HeapDumpOnOutOfMemoryError -jar *.jar

只要java进程内存不足,就会在进程的工作目录中生成栈转储文件(java_...hprof)。 生成堆转储后,该进程可以继续运行。通常,一个堆转储文件就足以分析问题。

注意: 如果您正在使用 crx-quickstart/server/start 脚本来启动 CRX 实例,则您可以添加 -XX:+HeapDumpOnOutOfMemoryErrorCQ_JVM_OPTS 变量(确保变量也未注释)。例如:

CQ_JVM_OPTS='-XX:+HeapDumpOnOutOfMemoryError'

添加此参数并重新启动 CRX 实例后,验证是否设置了新的 jvm 选项。 从命令行运行 ps -ef | grep java。 然后检查您是否看到-XX:+HeapDumpOnOutOfMemoryError作为CRX Java进程的参数。

如果由于磁盘空间限制需要指定不同的目录来生成堆转储,则可以添加 -XX:HeapDumpPath=/path/to/generate/heapdump 参数告诉 jvm 文件的放置位置。

有关调试相关jvm参数的引用,请参阅此处
手动生成栈转储
Sun/OracleJVM

要手动生成堆转储,请运行此命令(jmap 和 jps 可见于 jdk 主目录下的 bin 文件夹):

  1. 查找您正在为其生成栈转储的java进程的pid。

    • 在Unix或Linux中,此操作可以使用ps -ef | grep javajps -l完成
    • 在Windows中,这可以通过打开任务管理器来完成,按Ctrl+Shift+Esc,然后转到 查看,然后转到 选择列,然后转到 PID (进程标识符)jps -l
  2. 运行下面的 jmap 命令,使用您要生成堆转储文件的位置替换 /path/to/generate/heapdumpfile.hprof,然后使用您在上一步中查找的 pid 替换 1234

    code language-none
    jmap -dump:format=b,file=/path/to/generate/heapdumpfile.hprof 1234
    

IBM JVM

您首先必须更改有关转储代理的默认 JVM 设置,以便在用户信号上生成正确的转储。 有几种转储,但您通常需要完整的转储 系统转储 进行彻底的内存分析。添加以下参数:

Xdump:heap:opts=PHD+CLASSIC:events=user -Xdump:system:events=user

当JVM收到来自操作系统的SIGQUIT (Linux、AIX®、z/OS®和i5/OS™)或SIGBREAK (Windows)信号时,会发生此“用户”事件。

有关详细信息,请在此处参阅供应商的文档。

警告: 栈转储文件很大,在磁盘上的大小可以与最大栈 — Xmx jvm参数配置相同。 确保您有足够的磁盘空间分配给生成转储文件的目录。
分析栈转储
分析栈转储的好工具是EclipseMAT (Eclipse内存分析器)

此工具无法分析 IBM JVM 生成的转储。 对于以上问题,有几种可能性。 IBM HeapAnalyzer将适用于PHD或传统格式的栈转储。
[br>要进行完整的系统转储分析,请使用IBM支持助理工作台,其顶部安装有适用于Java的IBM监控和诊断工具 — 内存分析器。 栈直方图是对每个Java类使用的活动对象和内存数量的简单测量。 遗憾地是,所需的工具取决于Java安装,可能不可用或可能并不总是有效。 要创建栈直方图,您首先需要Java进程的进程ID。 要获取它,请运行ps or (if available), run:<b](br>要进行完整的系统转储分析,请使用IBM支持助理工作台,其顶部安装有适用于Java的IBM监控和诊断工具 — 内存分析器。 栈直方图是对每个Java类使用的活动对象和内存数量的简单测量。 遗憾地是,所需的工具取决于Java安装,可能不可用或可能并不总是有效。 要创建栈直方图,您首先需要Java进程的进程ID。 要获取它,请运行ps or (if available), run:<b)栈直方图
栈直方图是对每个Java类使用的活动对象和内存数量的简单测量。 遗憾地是,所需的工具取决于Java安装,可能不可用或可能并不总是有效。 要创建栈直方图,您首先需要Java进程的进程ID。 要得到该 ID,请运行 ps 或(如果可用),运行:

jps -l

此Java工具获取所有正在运行的Java进程的进程ID。 示例:

327
3332 sun.tools.jps.Jps
3313 crx-quickstart-....jar

现在,请运行以下命令:

jmap -histo 3313

该列表按所需的总内存排序(简略:不包括引用的对象)。输出的前 20 行是最有趣的。 输出示例:

JVM version is 1.5.0_20-141
Iterating over heap. This may take a while...
Warning: skipping invalid TLAB for thread t@62211
Warning: skipping invalid TLAB for thread t@62467
...
SizeCountClass description
-------------------------------------------------------
1059290412916byte`[` `]`
1028584075255* ConstMethodKlass
628317658388char`[` `]`
604230414928int`[` `]`
4995752116201* SymbolKlass
422089675255* MethodKlass
41965126969* ConstantPoolKlass
29285606969* InstanceKlassKlass
26310086066* ConstantPoolCacheKlass
2395872149742org.apache.jackrabbit.core.query.lucene.DocId$PlainDocId
14760087003java.util.HashMap$Entry`[` `]`
139612858172java.lang.String
107023244593java.util.HashMap$Entry
75398410036short`[` `]`
73546454org.apache.jackrabbit.core.query.lucene.DocId`[` `]`
7201927502java.lang.Class
64070413348com.day.crx.persistence.tar.index.IndexEntry
...

其他信息

为了帮助分析问题,我们还需要了解以下信息:

  • CRX 或 CQ 版本,包括所有已安装修补程序版本号的列表。
  • 操作系统版本、JVM 供应商和版本。

引用

[ 1] HotSpot VM的Oracle帮助中心>故障排除指南
[ 2]  Oracle.com > javas > DebuggingOptions

recommendation-more-help
3d58f420-19b5-47a0-a122-5c9dab55ec7f