我们的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
`
那里没有骰子。再次,我的集会可以追溯到第二波斯卡,所以我 只能认为堆栈有点错误,或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
反汇编(看起来像是读取+ 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) );
}
感谢。
答案 0 :(得分:1)
我们的生产服务器上遇到了同样的问题。问题基本上是JNI代码中的堆栈溢出,它被隐藏为段错误:http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=7059899
尝试使用jstack从VM生成的核心文件中提取线程转储,并查找无限循环。
答案 1 :(得分:0)
getFdEntry是宏还是内联?我会在那里看看。基于汇编代码转储,seg错误发生在第一个分支之前,就在初始堆栈操作之后,这使得它看起来像是在getFdEntry中的某个地方。此外,鉴于对读取的调用包含在看起来像锁定/解锁操作的可疑内容中,我认为您对竞争条件的怀疑可能是好的。在没有看到其余的源代码的情况下很难说,但我最好的猜测是getFdEntry是一个内联函数,它不像应该的那样是线程安全的