Java 8中的java.util.logging.FileHandler是否已损坏? [英] Is java.util.logging.FileHandler in Java 8 broken?

查看:177
本文介绍了Java 8中的java.util.logging.FileHandler是否已损坏?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

首先,一个简单的测试代码:

First, a simple test code:

package javaapplication23;

import java.io.IOException;
import java.util.logging.FileHandler;

public class JavaApplication23 {
    public static void main(String[] args) throws IOException {
        new FileHandler("./test_%u_%g.log", 10000, 100, true);
    }
}

此测试代码仅使用Java 7创建一个文件 test_0_0.log,无论我多久运行一次程序。这是预期的行为,因为构造函数中的append参数设置为true。

This test code creates with Java 7 only one File "test_0_0.log", no matter, how often I run the program. This is the expected behaviour because the append parameter in the constructor is set to true.

但是如果我在Java 8中运行此示例,则每次运行都会创建一个新文件(test_0_0) .log,test_0_1.log,test_0_2.log,...)。我认为这是一个错误。

But if I run this sample in Java 8, every run creates a new File (test_0_0.log, test_0_1.log, test_0_2.log,...). I think this is a bug.

Imho,Java中的相关变化是这样的:

Imho, the related change in Java is this one:

@@ -413,18 +428,18 @@
                     // object.  Try again.
                     continue;
                 }
-                FileChannel fc;
+
                 try {
-                    lockStream = new FileOutputStream(lockFileName);
-                    fc = lockStream.getChannel();
-                } catch (IOException ix) {
-                    // We got an IOException while trying to open the file.
-                    // Try the next file.
+                    lockFileChannel = FileChannel.open(Paths.get(lockFileName),
+                            CREATE_NEW, WRITE);
+                } catch (FileAlreadyExistsException ix) {
+                    // try the next lock file name in the sequence
                     continue;
                 }
+
                 boolean available;
                 try {
-                    available = fc.tryLock() != null;
+                    available = lockFileChannel.tryLock() != null;
                     // We got the lock OK.
                 } catch (IOException ix) {
                     // We got an IOException while trying to get the lock.
@@ -440,7 +455,7 @@
                 }

                 // We failed to get the lock.  Try next file.
-                fc.close();
+                lockFileChannel.close();
             }
         }

(完整: OpenJDK变更集6123:ac22a52a732c

我知道通常FileHandler会被Logmanager关闭,但如果系统或应用程序崩溃或进程被终止,情况就不是这样了。这就是为什么我在上面的示例代码中没有关闭声明。

I know that normally the FileHandler gets closed by the Logmanager, but this is not the case, if the system or the application crashes or the process gets killed. This is why I do not have a "close" statement in the above sample code.

现在我有两个问题:

1)您有什么看法?这是一个错误吗? (几乎在以下评论和答案中回答)

1) What is your opinion? Is this a bug? (Almost answered in the following comments and answers)

2)您是否知道在Java 8中获取旧Java 7行为的解决方法? (更重要的问题......)

2) Do you know a workaround to get the old Java 7 behavior in Java 8? (The more important question...)

感谢您的回答。

推荐答案

关闭FileHandler会删除'lck'文件。如果锁文件完全存在于 JDK8版本下小于update 40(java.util.logging),FileHandler将旋转。从 OpenJDK 讨论中,如果当前进程无法锁定lck文件,则决定始终旋转。给出的原因是当锁文件存在时旋转总是更安全。因此,如果您使用混合JDK版本的旋转模式,这会变得非常讨厌,因为JDK7版本将重用锁,但JDK8版本将保留并旋转。您正在使用测试用例。

Closing of the FileHandler deletes the 'lck' file. If the lock file exists at all under a JDK8 version that is less than update 40 (java.util.logging), the FileHandler is going to rotate. From the OpenJDK discussion, the decision was made to always rotate if the lck file exists in addtion to if the current process can't lock it. The reason given is that it is always safer to rotate when the lock file exists. So this gets really nasty if you have rotating pattern in use with a mix of JDK versions because the JDK7 version will reuse the lock but the JDK8 version will leave it and rotate. Which is what you are doing with your test case.

如果我从工作目录中清除所有日志和lck文件,则使用JDK8然后运行:

Using JDK8 if I purge all log and lck files from the working directory and then run:

public static void main(String[] args) throws IOException {
    System.out.println(System.getProperty("java.runtime.version"));
    new FileHandler("./test_%u.log", 10000, 100, true).close();
}

我总是看到一个名为'test_0.log.0'的文件。我使用JDK7获得相同的结果。

I always see a file named 'test_0.log.0'. I get the same result using JDK7.

底线是你必须确保你的FileHandler被关闭。如果它从未被收集或从记录树中删除,则LogManager将关闭你的FileHandler。否则你必须关闭它。修复此问题后,在运行新的修补代码之前清除所有锁定文件。然后请注意,如果JVM进程崩溃或被杀死,则不会删除锁定文件。如果关闭时出现I / O错误,则不会删除锁定文件。当下一个进程启动时,FileHandler将会旋转。

Bottom line is that is that you have to ensure your FileHandlers are closed. If it is never garbaged collected or removed from the logger tree then LogManager will close your FileHandler. Otherwise you have to close it. After that is fixed, purge all lock files before running your new patched code. Then be aware that if the JVM process crashed or is killed the lock file won't be deleted. If you have an I/O error on close your lock file won't be deleted. When the next process starts, the FileHandler will rotate.

正如您所指出的,如果上述条件发生,可能会耗尽JDK8上的所有锁定文件100次运行。对此的一个简单测试是运行以下代码两次而不删除log和lck文件:

As you point out, it is possible to use up all of the lock files on JDK8 if the above conditions occur over 100 runs. A simple test for this is to run the following code twice without deleting the log and lck files:

public static void main(String[] args) throws Exception {
    System.out.println(System.getProperty("java.runtime.version"));
    ReferenceQueue<FileHandler> q = new ReferenceQueue<>();
    for (int i=0; i<100; i++) {
        WeakReference<FileHandler> h = new WeakReference<>(
                new FileHandler("./test_%u.log", 10000, 2, true), q);
        while (q.poll() != h) {
            System.runFinalization();
            System.gc();
            System.runFinalization();
            Thread.yield();
        }
    }
}

但是,上面的测试用例如果正确修复了 JDK-6774110 ,则无效。可以在OpenJDK网站上的 RFR:8048020 - 对java.util.logging.FileHandler的回归 FileHandler webrev

However, the test case above won't work if JDK-6774110 is fixed correctly. The issue for this can be tracked on the OpenJDK site under RFR: 8048020 - Regression on java.util.logging.FileHandler and FileHandler webrev.

这篇关于Java 8中的java.util.logging.FileHandler是否已损坏?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆