编程语言
首页 > 编程语言> > Java 8中的java.util.logging.FileHandler是否已损坏?

Java 8中的java.util.logging.FileHandler是否已损坏?

作者:互联网

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

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.

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

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

@@ -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 changeset 6123:ac22a52a732c)

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

现在我有两个问题:

1)你的意见是什么?这是一个错误吗? (几乎在以下评论和答案中回答)

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

谢谢你的回答.

解决方法:

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

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

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获得相同的结果.

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

正如您所指出的,如果上述条件超过100次运行,则可能会耗尽JDK8上的所有锁定文件.对此进行简单测试是在不删除日志和lck文件的情况下运行以下代码两次:

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 – Regression on java.util.logging.FileHandlerFileHandler webrev上跟踪此问题.

标签:java,java-8,logging,filehandler
来源: https://codeday.me/bug/20191001/1837636.html