我在使用GC日志的几台服务器上遇到问题。它充满了这个:
^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@
^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@
^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@
注意到这发生在给JVM提供大量内存的服务器上:-Xms32G -Xmx48G
。这可能是一个红鲱鱼,但想提到它。
由于这些是低延迟/高吞吐量的应用程序,分析日志至关重要。但相反,它充满了上面的那些角色。
我们正在使用Java 8:
java version "1.8.0_40"
Java(TM) SE Runtime Environment (build 1.8.0_40-b26)
Java HotSpot(TM) 64-Bit Server VM (build 25.40-b25, mixed mode)
我们使用它来创建日志:
-verbose:gc
-Xloggc:/path/to/gc.log
-XX:+PrintGCDetails
-XX:+PrintGCDateStamps
之前有人见过这个问题吗?可能导致什么呢?
答案 0 :(得分:4)
请勿使用logrotate
(或任何第三者轮换)来轮换JVM GC日志。它的行为与JVM写入GC日志文件的方式不太匹配。 JVM可以使用JVM标志来轮换自己的GC日志:
-XX:+UseGCLogFileRotation
启用GC日志文件轮换-XX:NumberOfGCLogFiles=5
将告诉JVM保留5个旋转文件-XX:GCLogFileSize=20M
将在文件达到20M时通知JVM旋转对我们来说,这是因为logrotate
和JVM都试图在不加锁的情况下写入文件。 JVM垃圾回收日志看起来很特殊,因为它们是直接从JVM本身写入文件的。发生的情况是,JVM保留了该文件的句柄,以及该文件中写入日志的位置。
^@
实际上只是文件中的一个空字节。如果运行hexdump -C your_gc.log
,则可以看到此信息。引起这些空字节的原因是有趣的部分-logrotate
截断文件。
$ hexdump -C gc.log | head -3
00000000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
061ca010 00 00 00 00 00 00 00 32 30 32 30 2d 30 37 2d 30 |.......2020-07-0|
这仅对我们浮出水面,因为我们使用Logstash监视GC日志。每次OutOfMemoryError
运行时,Logstash都因logrotate
而崩溃,并且从检查堆转储中我们注意到,logstash试图发送看起来像这样的HUGE(JVM内部存储器中为600MB)日志行:
{ "message": "\u0000\u0000\u0000...
在这种情况下,因为logstash将空值转义为Unicode(6个字符),并且每个字符在JVM中内部表示为UTF-16,所以这意味着其堆上编码比12的大倍。磁盘上的空字节。因此,它所需要的日志要比您用尽的内存少。
这导致我们在垃圾收集日志中找到空值以及它们的来源:
*-------------------------*
^ ^
JVM's file start JVM's current location
logrotate
已进入游戏 **
\________________________/
^ | ^
JVM's file start | JVM's current location
|
logrotate copies contents elsewhere and truncates file
to zero-length
*xxxxxxxxxxxxxxxxxxxxxxxxx-*
\________________________/^^
^ | |JVM's current location
JVM's file start | JVM writes new log
|
File is now zero-length, but JVM still tries to write
to the end, so everything before it's pointer is
filled in with zeros
答案 1 :(得分:1)
如果您保存的文字是用UTF-16编码的,它可能附加一个" ^ @"在常规文本文件中。我以前在UNIX系统中打开一些编码文件时遇到了这个问题。