【问题标题】:No hs_err_pid.log file created and core dumped from jvm on Solaris没有创建 hs_err_pid.log 文件并从 Solaris 上的 jvm 转储核心
【发布时间】:2011-09-26 12:54:03
【问题描述】:

问题描述

在运行我的 Java 服务器应用程序一段时间后,我在 Solaris 上遇到了 Oracle Java 虚拟机的奇怪行为。通常,当 jvm 崩溃时,hs_err_pid.log 文件被创建(位置由-XX:ErrorFile jvm 参数确定,如下所述:How can I suppress the creation of the hs_err_pid file?

但在我的情况下,该文件没有创建,唯一剩下的是core核心转储文件。

使用pstackpflags 标准Solaris 工具,我能够从core 文件中收集有关崩溃的更多信息(包括在下面)。

尝试过的解决方案

  • 尝试在文件系统中查找所有hs_err_pid.log 文件,但找不到任何东西(即使在应用程序工作目录之外)。即:

    find / -name "hs_err_pid*"

  • 我试图查找与 jvm 相关的 jvm 错误,但我找不到与此案例类似的有趣内容。

  • 问题看起来有点类似于:Java VM: reproducable SIGSEGV on both 1.6.0_17 and 1.6.0_18, how to report?,但我仍然无法确认这一点,因为缺少hs_err_pid.log 文件,当然操作系统平台也不同。
  • (编辑) 正如Tool for analyzing java core dump 问题的答案之一所建议的,我已经使用jmapcore 文件中提取了堆转储,并使用Eclipse MAT 对其进行了分析。我发现了一个泄漏(在核心转储 1,4 M 个元素时,添加到 HashMap 的元素永远不会被清理)。然而,这并不能解释为什么没有生成 hs_err_pid.log 文件,也没有解释 jvm 崩溃的原因。
  • (EDIT2) 正如 Darryl Miles 所建议的,已检查 -Xmx 限制(测试包含无限期将对象添加到 LinkedList 的代码):
    • java -Xmx1444m Test 结果与java.lang.OutOfMemoryError: Java heap space
    • java -Xmx2048m Test 结果与java.lang.OutOfMemoryError: Java heap space
    • java -Xmx3600m Test 结果与核心转储。

问题

有没有人遇到过类似的 jvm 问题以及如何在这种情况下继续查找实际发生的情况(即在什么情况下核心从 jvm 转储并且没有创建 hs_err_pid.log 文件)?

任何解决此问题的提示或指针都会非常有帮助。

提取的标志

# pflags core
...
/2139095:      flags = DETACH
    sigmask = 0xfffffeff,0x0000ffff  cursig = SIGSEGV

提取的堆栈

# pstack core
...
-----------------  lwp# 2139095 / thread# 2139095  --------------------
 fb208c3e ???????? (f25daee0, f25daec8, 74233960, 776e3caa, 74233998, 776e64f0)
 fb20308d ???????? (0, 1, f25db030, f25daee0, f25daec8, 7423399c)
 fb20308d ???????? (0, 0, 50, f25da798, f25daec8, f25daec8)
 fb20308d ???????? (0, 0, 50, f25da798, 8561cbb8, f25da988)
 fb203403 ???????? (f25da988, 74233a48, 787edef5, 74233a74, 787ee8a0, 0)
 fb20308d ???????? (0, f25da988, 74233a78, 76e2facf, 74233aa0, 76e78f70)
 fb203569 ???????? (f25da9b0, 8b5b400, 8975278, 1f80, fecd6000, 1)
 fb200347 ???????? (74233af0, 74233d48, a, 76e2fae0, fb208f60, 74233c58)
 fe6f4b0b __1cJJavaCallsLcall_helper6FpnJJavaValue_pnMmethodHandle_pnRJavaCallArguments_pnGThread__v_ (74233d44, 74233bc8, 74233c54, 8b5b400) + 1a3
 fe6f4db3 __1cCosUos_exception_wrapper6FpFpnJJavaValue_pnMmethodHandle_pnRJavaCallArguments_pnGThread__v2468_v_ (fe6f4968, 74233d44, 74233bc8, 74233c54, 8b5b4
00) + 27
 fe6f4deb __1cJJavaCallsEcall6FpnJJavaValue_nMmethodHandle_pnRJavaCallArguments_pnGThread__v_ (74233d44, 8975278, 74233c54, 8b5b400) + 2f
 fe76826d __1cJJavaCallsMcall_virtual6FpnJJavaValue_nLKlassHandle_nMsymbolHandle_4pnRJavaCallArguments_pnGThread__v_ (74233d44, 897526c, fed2d464, fed2d6d0, 7
4233c54, 8b5b400) + c1
 fe76f4fa __1cJJavaCallsMcall_virtual6FpnJJavaValue_nGHandle_nLKlassHandle_nMsymbolHandle_5pnGThread__v_ (74233d44, 8975268, 897526c, fed2d464, fed2d6d0, 8b5b
400) + 7e
 fe7805f6 __1cMthread_entry6FpnKJavaThread_pnGThread__v_ (8b5b400, 8b5b400) + d2
 fe77cbe4 __1cKJavaThreadRthread_main_inner6M_v_ (8b5b400) + 4c
 fe77cb8e __1cKJavaThreadDrun6M_v_ (8b5b400) + 182
 feadbd59 java_start (8b5b400) + f9
 feed59a9 _thr_setup (745c5200) + 4e
 feed5c90 _lwp_start (745c5200, 0, 0, 74233ff8, feed5c90, 745c5200)

系统信息:

# uname -a
SunOS xxxx 5.10 Generic_137138-09 i86pc i386 i86pc
# java -version
java version "1.6.0_11"
Java(TM) SE Runtime Environment (build 1.6.0_11-b03)
Java HotSpot(TM) Server VM (build 11.0-b16, mixed mode)
# ulimit -a
time(seconds) unlimited
file(blocks) unlimited
data(kbytes) unlimited
stack(kbytes) 10240
coredump(blocks) unlimited
nofiles(descriptors) 256
memory(kbytes) unlimited

使用的 jvm 参数:

java -Xms1024M -Xmx2048M -verbose:gc -Xloggc:logs/gc.log -server com.example.MyApplication

如果您发现缺少某些信息,请发表评论,我会尝试添加它们。

【问题讨论】:

  • JVM 可以写启动目录和/或当前工作目录吗?你认为崩溃的原因是内存泄漏,对象太多,看到任何核心文件是不寻常的这应该发生一个优雅的 OutOfMemoryError。除非有一些 JNI 错误。崩溃处理程序(写出 hs_err_pid*.log 的代码)可能会崩溃。也许在正在运行的进程上运行系统调用跟踪以观察它在其生命结束时所做的事情(即您应该能够查看崩溃处理程序是否崩溃,以及它是否尝试创建任何文件 hs_err_pid*.log)。在 Linux 上Solaris“桁架”上的“strace”
  • 感谢您的回答。我确信工作目录是可写的(原因有两个:jvm 是以 root 权限运行的,并且它在前面已经成功编写过)。一般来说,应用程序本身不使用 jni 代码,也不是 jar 依赖项。但问题还是一样,为什么核心转储而没有 hs_rr_pid*.log 文件? Solaris内核是否有可能发送“核心转储”信号之一,即:developers.sun.com/solaris/articles/signalprimer.html
  • 如果你逐渐减少 -Xmx1700M 可以让进程抛出 OutOfMemoryError 吗?在 Solaris 上最大可用的 -Xmx 值是多少,例如,在 32 位 Windows 上大约是 1800M(因为默认情况下内核的上限为 2Gb,而 DLL/共享数据/堆栈占用大约 200M。您是否设法在获得有用输出的过程?您的“ulimit -a”设置是什么(例如来自 bash shell)。
  • 那么你的意思是,低堆栈限制,过多的虚拟机使用可能会导致这种情况?
  • 这并不是一个低堆栈限制,除非你正在做大量的回收并需要大量的堆栈空间。 “ulimit -Ha”可能表示硬限制是无限的,我希望 JVM 可以根据需要进行相应的管理。 JVM 堆栈和 C 语言堆栈是不同的。程序有多少个应用程序线程?我希望“truss”可以指示发生了什么信号,以及是否/何时用尽堆(内核拒绝通过 brk/sbrk 系统调用提供更多堆。在 Linux 下,所有这些都可以使用“strace”进行审计)。我建议通过减少 -Xmx 您可能可以获得受控的 OOM。

标签: java jvm solaris segmentation-fault jvm-crash


【解决方案1】:

6.0_11 比较老了,最近没用过,真心推荐升级一下。。。

但是,在本机代码中,stackoverflow 不会发生崩溃转储,即调用一些具有非常低堆栈的本机函数(如 FileOutputStream 的写入,套接字使用相同的 impl)。因此,即使 JVM 尝试写入文件,也没有足够的堆栈,写入代码也会崩溃。 第二个 stackoverflow 只是解决了这个过程。

我在生产系统上确实有类似的情况(没有创建文件),跟踪它并不好,但上面解释了原因。

【讨论】:

  • 据我了解,除了 JRE/JDK 提供的代码(根据 pkk 注释#2)之外,没有其他本地代码。然而,堆限制看起来已经用尽,因此减少 -Xmx 以使 JVM 在内核开始拒绝新的内存分配请求之前通过 OOM 失败,因为没有更多的堆。这为 JVM 提供了喘息的空间,以便通过仍然可以工作的内存空间来优雅地恢复。
  • 您希望 JVM 监管内存限制,而 JVM 本身仍然可以从内核请求并获取更多内存来执行自己的内部操作。将 -Xmx 设置得太高会导致内核执行限制意味着 JVM 的内部操作也因“铁路”耗尽而失败。所以问题是 Solaris 32 位系统的 -Xmx 的合理值是多少?我知道对于 Windows 32 位,它大约为 1800M,所以你想低于那个,但它可能取决于 DLL/共享数据/线程堆栈也将竞争相同的进程地址空间。也许 pkk 可以使用 64 位 JVM 并且问题消失?
  • @Darryl,我说的是堆栈而不是堆(您可以通过 -Xmx 设置),并且 JVM 有本机代码,相当多。就像我告诉 FileOutputStream 一样,FileInputStream 在本机代码中执行真正的写入/读取。 32 位系统受限于它们可以分配的虚拟内存的大的连续内存块。
  • 在我看来,如果您正在使用任何需要在单个进程(在任何操作系统上)中使用超过 1.5Gb 内存作为工作集的应用程序,那么您应该认真考虑 64 位。很难证明有理由将自己束缚在技术变通方法中以将程序硬塞到 32 位范式中。上次我查看了运行 64 位 JVM 的 Solaris,只需要在 java 命令行上使用“-d64”。 “java -d64 -server -version”?
  • @Darryl,我通常不使用 32 位 java,绝对不用于生产。
【解决方案2】:

根据我上面的 cmets。我相信这个问题是因为设置了太高的 -Xmx 值而导致 32 位地址空间中的可用堆用完。这迫使内核在 JVM 可以监管它(通过使用受控的 OutOfMemoryException 机制)之前监管该限制(通过拒绝对新内存的请求)。不幸的是,我不知道英特尔 Solaris 的细节,无法知道该平台的预期。

但作为 Windows 的一般规则,最大 -Xmx 可能为 1800M,然后您创建的每个附加应用程序线程将其减少 16M。由于每个线程都需要堆栈空间(本机堆栈和 Java 堆栈)以及其他每个线程的会计事项,例如线程本地存储等......这个计算的结果应该为您提供 Java VM 的实际可用堆空间的近似值在操作系统使用 2G/2G 拆分(用户/内核)的任何 32 位进程上。

在 WinXP 及以上版本中,可以在内核上使用 /3G 开关来获得更高的分割(3G/1G 用户/内核),并且 Linux 有一个 /proc//map 文件可以让您准确了解如何操作进程地址空间由给定进程布局(如果您正在运行此应用程序,您可以随着时间的推移观察 [heap] 增长以满足用于 .text/.rodata/.data/etc 的共享文件映射...对于 DSO,这会导致内核拒绝增加堆的请求。

这个问题在 64 位上消失了,因为有更多的地址空间可供使用,并且在堆遇到其他映射之前,您将用完物理和虚拟(交换)内存。

我相信 Solaris 上的“truss”会在核心转储前不久显示返回错误代码的 brk/sbrk 系统调用。部分标准本机库被编码为从不检查新内存请求的返回代码,因此可能会发生崩溃。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-11
    • 2011-03-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多