【问题标题】:Sun JVM (JRE jre1.6.0_24) segfault NET_ReadSun JVM (JRE jre1.6.0_24) 段错误 NET_Read
【发布时间】:2011-09-21 10:55:03
【问题描述】:

我们的 JVM 在 感觉像是某种竞赛条件的生产。

重现的设置: - Linux Ubuntu 9.10 和 Debian 4.x 64 位多核 AMD 上的 JRE jre1.6.0_24 - Apache tomcat 6.0.24 ... 6.0.32

用 fastdebug 重新编译 java 会重现问题(这个 gcc -g1)。 然而,它并没有产生比我们更多有用的信息 在这里。

用 debug 重新编译 java 不会重现问题(这是 gcc -g 可能加上一些 -DSOMETHING 代码调试标志)。

任何试图解决这个问题的帮助将不胜感激。

使用 Oracle 的 1.6.0_24 jdk 生成的核心文件。 gdb 出现:

    Program terminated with signal 11, Segmentation fault.
    #0  0x00002aaab7b10666 in NET_Read () from
    /usr/local/jdk1.6.0_24/jre/lib/amd64/libnet.so

好的,所以我的组件真的生锈了。牢记这一点:

    (gdb) info frame
    Stack level 0, frame at 0x4b3e0040:
     rip = 0x2aaab7b10666 in NET_Read; saved rip 0x2aaab7b0d53b
     called by frame at 0x4b3f0090
             Arglist at 0x4b3dffc8, args:
     Locals at 0x4b3dffc8, Previous frame's sp is 0x4b3e0040
     Saved registers:
     rbx at 0x4b3e0008, rbp at 0x4b3e0010, r12 at 0x4b3e0018, r13 at
    0x4b3e0020, r14 at 0x4b3e0028, r15 at 0x4b3e0030, rip at 0x4b3e0038

所以,gdb 告诉我们参数列表位于:

    0x4b3dffc8

查看那里的数据:

    (gdb) x/8x 0x4b3dffc8
    0x4b3dffc8:     0x00000000      0x00000000      0x00000000      0x00000000
    0x4b3dffd8:     0x00000000      0x00000000      0x00000000      0x00000000

`

所以那里没有骰子。同样,我的装配可以追溯到第二波 ska,所以我 只能认为要么是堆栈有些bug,要么是gcc 优化标志生成使用寄存器作为参数的代码 而不是堆栈?

到寄存器上:

    (gdb) info registers
    rax            0xf2     242
                                                    rbx            0x4      4
    rcx            0x2b73aa8bfed3   47775782534867
    rdx            0x4      4
    rsi            0x4b3e0050       1262354512
            rdi            0xf2     242
    rbp            0x0      0x0
    rsp            0x4b3dffd0       0x4b3dffd0
    r8             0xffc    4092
    r9             0x2b73aa8c61b0   47775782560176
    r10            0x2b73aa8c9f78   47775782575992
    r11            0x2b73aa8b20d0   47775782478032
    r12            0xf2     242
    r13            0xf2     242
    r14            0x2aaabad4b9c8   46912767310280
    r15            0x4      4
    rip            0x2aaab7b10666   0x2aaab7b10666 <NET_Read+22>
    eflags         0x10202  [ IF RF ]
    cs             0x33     51
    ss             0x2b     43
    ds             0x0      0
    es             0x0      0
    fs             0x63     99
    gs             0x0      0

反汇编(在我看来它在 Read+22 时出错):

    0x00002aaab7b10650 <NET_Read+0>:        push   %r15
            0x00002aaab7b10652 <NET_Read+2>:        mov    %rdx,%r15
    0x00002aaab7b10655 <NET_Read+5>:        push   %r14
                            0x00002aaab7b10657 <NET_Read+7>:        push   %r13
    0x00002aaab7b10659 <NET_Read+9>:        mov    %edi,%r13d
    0x00002aaab7b1065c <NET_Read+12>:       push   %r12
    0x00002aaab7b1065e <NET_Read+14>:       push   %rbp
    0x00002aaab7b1065f <NET_Read+15>:       push   %rbx
    0x00002aaab7b10660 <NET_Read+16>:       sub    $0x38,%rsp
    0x00002aaab7b10664 <NET_Read+20>:       test   %edi,%edi
    0x00002aaab7b10666 <NET_Read+22>:       mov    %rsi,0x8(%rsp)
    0x00002aaab7b1066b <NET_Read+27>:       js     0x2aaab7b1067c <NET_Read+44>
    0x00002aaab7b1066d <NET_Read+29>:       lea    1073812(%rip),%rax
     # 0x2aaab7c16908 <fdCount>
    0x00002aaab7b10674 <NET_Read+36>:       cmp    (%rax),%edi
    0x00002aaab7b10676 <NET_Read+38>:       jle    0x2aaab7b1070b <NET_Read+187>
    0x00002aaab7b1067c <NET_Read+44>:       xor    %ebp,%ebp
    0x00002aaab7b1067e <NET_Read+46>:       test   %rbp,%rbp
    0x00002aaab7b10681 <NET_Read+49>:       je     0x2aaab7b106f9 <NET_Read+169>
    0x00002aaab7b10683 <NET_Read+51>:       lea    0x10(%rsp),%r14
    0x00002aaab7b10688 <NET_Read+56>:       callq  0x2aaab7b03dd0 <pthread_self@plt>
    0x00002aaab7b1068d <NET_Read+61>:       mov    %rbp,%rdi
    0x00002aaab7b10690 <NET_Read+64>:       movl   $0x0,0x20(%rsp)
    0x00002aaab7b10698 <NET_Read+72>:       mov    %rax,0x10(%rsp)
    0x00002aaab7b1069d <NET_Read+77>:       callq  0x2aaab7b03f80
    <pthread_mutex_lock@plt>
    0x00002aaab7b106a2 <NET_Read+82>:       mov    %rbp,%rdi
    0x00002aaab7b106a5 <NET_Read+85>:       mov    0x28(%rbp),%rax
    0x00002aaab7b106a9 <NET_Read+89>:       mov    %rax,0x18(%rsp)
    0x00002aaab7b106ae <NET_Read+94>:       mov    %r14,0x28(%rbp)
    0x00002aaab7b106b2 <NET_Read+98>:       callq  0x2aaab7b043b0
    <pthread_mutex_unlock@plt>
    0x00002aaab7b106b7 <NET_Read+103>:      mov    %r13d,%edi
    0x00002aaab7b106ba <NET_Read+106>:      mov    0x8(%rsp),%rsi
    0x00002aaab7b106bf <NET_Read+111>:      xor    %ecx,%ecx
    0x00002aaab7b106c1 <NET_Read+113>:      mov    %r15,%rdx
    0x00002aaab7b106c4 <NET_Read+116>:      callq  0x2aaab7b04160 <recv@plt>
    0x00002aaab7b106c9 <NET_Read+121>:      mov    %rbp,%rdi
    0x00002aaab7b106cc <NET_Read+124>:      mov    %r14,%rsi
    0x00002aaab7b106cf <NET_Read+127>:      mov    %eax,%ebx
    0x00002aaab7b106d1 <NET_Read+129>:      mov    %rax,%r12
    0x00002aaab7b106d4 <NET_Read+132>:      callq  0x2aaab7b11000 <endOp>
    0x00002aaab7b106d9 <NET_Read+137>:      inc    %ebx
    0x00002aaab7b106db <NET_Read+139>:      jne    0x2aaab7b106e7 <NET_Read+151>
    0x00002aaab7b106dd <NET_Read+141>:      callq  0x2aaab7b04380
    <__errno_location@plt>
    0x00002aaab7b106e2 <NET_Read+146>:      cmpl   $0x4,(%rax)
    0x00002aaab7b106e5 <NET_Read+149>:      je     0x2aaab7b10688 <NET_Read+56>
    0x00002aaab7b106e7 <NET_Read+151>:      mov    %r12d,%eax
    0x00002aaab7b106ea <NET_Read+154>:      add    $0x38,%rsp
    0x00002aaab7b106ee <NET_Read+158>:      pop    %rbx
    0x00002aaab7b106ef <NET_Read+159>:      pop    %rbp
    0x00002aaab7b106f0 <NET_Read+160>:      pop    %r12
    0x00002aaab7b106f2 <NET_Read+162>:      pop    %r13
            0x00002aaab7b106f4 <NET_Read+164>:      pop    %r14
            0x00002aaab7b106f6 <NET_Read+166>:      pop    %r15
            0x00002aaab7b106f8 <NET_Read+168>:      retq
            0x00002aaab7b106f9 <NET_Read+169>:      callq  0x2aaab7b04380
    <__errno_location@plt>
    0x00002aaab7b106fe <NET_Read+174>:      movl   $0x9,(%rax)
    0x00002aaab7b10704 <NET_Read+180>:      mov    $0xffffffff,%eax
    0x00002aaab7b10709 <NET_Read+185>:      jmp    0x2aaab7b106ea <NET_Read+154>
    0x00002aaab7b1070b <NET_Read+187>:      movslq %edi,%rax
    0x00002aaab7b1070e <NET_Read+190>:      lea    (%rax,%rax,2),%rbp
    0x00002aaab7b10712 <NET_Read+194>:      lea    1073639(%rip),%rax
     # 0x2aaab7c16900 <fdTable>
    0x00002aaab7b10719 <NET_Read+201>:      shl    $0x4,%rbp
    0x00002aaab7b1071d <NET_Read+205>:      add    (%rax),%rbp
    ---Type <return> to continue, or q <return> to quit---
    0x00002aaab7b10720 <NET_Read+208>:      jmpq   0x2aaab7b1067e <NET_Read+46>
    0x00002aaab7b10725 <NET_Read+213>:      data16
    0x00002aaab7b10726 <NET_Read+214>:      data16
    0x00002aaab7b10727 <NET_Read+215>:      data16
    0x00002aaab7b10728 <NET_Read+216>:      nop
    0x00002aaab7b10729 <NET_Read+217>:      data16
    0x00002aaab7b1072a <NET_Read+218>:      data16
    0x00002aaab7b1072b <NET_Read+219>:      data16
    0x00002aaab7b1072c <NET_Read+220>:      nop
    0x00002aaab7b1072d <NET_Read+221>:      data16
    0x00002aaab7b1072e <NET_Read+222>:      data16
    0x00002aaab7b1072f <NET_Read+223>:      nop

查看 NETRead 的源代码:

    jdk/src/solaris/native/java/net/linux_close.c

    *snip*
    /*
             * Macro to perform a blocking IO operation. Restarts
     * automatically if interrupted by signal (other than
             * our wakeup signal)
     */
    #define BLOCKING_IO_RETURN_INT(FD, FUNC) {      \
       int ret;                                    \
       threadEntry_t self;                         \
               fdEntry_t *fdEntry = getFdEntry(FD);        \
               if (fdEntry == NULL) {                      \
           errno = EBADF;                          \
           return -1;                              \
       }                                           \
       do {                                        \
           startOp(fdEntry, &self);                \
           ret = FUNC;                             \
           endOp(fdEntry, &self);                  \
       } while (ret == -1 && errno == EINTR);      \
       return ret;                                 \
    }

    int NET_Read(int s, void* buf, size_t len) {
       BLOCKING_IO_RETURN_INT( s, recv(s, buf, len, 0) );
    }

谢谢。

【问题讨论】:

  • 可重现的 JVM 崩溃很有趣:这是我的一个...stackoverflow.com/questions/2299250 人们会告诉你,如果你的发行版没有得到官方支持,你就是 SOL(恕我直言有点傻,但是随便;)
  • 我很好奇您从哪里获得了用于重新编译的 Sun Java 源代码。但是是的 - 1)你肯定有 64 位 JVM(“rax”、“rcx”等),2)你说它是 Sun JVM,直接来自 Oracle,3)你说你可以通过以下方式重现问题用“fastdebug”编译,它用“-g”消失......所以4)我只能说这是这个Java版本的GCC优化器的问题。问:你试过不同的版本了吗?
  • 你的“装配体”确实生锈了:它被称为“装配体”;)
  • “任何试图解决这个问题的帮助将不胜感激。”:您希望实现什么目标? JVM 中的 SEGV 表明 JVM 或某些 JNI 代码中存在错误。该程序是否有您自己编写的任何 JNI?如果没有,您所能做的就是向 Oracle 提交错误报告。他们应该感谢你,因为你已经超越了典型的错误报告。

标签: java sockets jvm segmentation-fault


【解决方案1】:

我们在生产服务器上遇到了同样的问题。问题基本上是隐藏为段错误的 JNI 代码中的堆栈溢出:http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=7059899

尝试使用 jstack 从 VM 生成的核心文件中提取线程转储并查找无限循环。

【讨论】:

    【解决方案2】:

    getFdEntry 是宏还是内联?我会进去看看。根据汇编代码转储,段错误发生在第一个分支之前,就在初始堆栈操作之后,这使得它看起来在 getFdEntry 中的某个地方。此外,鉴于对读取的调用包含在看起来可疑的锁定/解锁操作中,我认为您对竞争条件的怀疑可能是好的。没有看到其余的源代码很难说,但我最好的猜测是 getFdEntry 是一个内联函数,它不像它应该的那样线程安全

    【讨论】:

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