Java 文件.getLastModifiedTime()是否正在泄漏内存?

Java 文件.getLastModifiedTime()是否正在泄漏内存?,java,memory-leaks,jvm,java-8,java.nio.file,Java,Memory Leaks,Jvm,Java 8,Java.nio.file,我遇到了一个bug,其中一个服务器应用程序几乎每秒都在使用越来越多的内存,我成功地筛选出了一个仍然显示这种行为的简短示例: public class TestGetLastModifiedTime { private static final Path PATH = Paths.get("D:\\test.txt"); private static final ScheduledExecutorService SCHEDULER = Executors.newScheduledT

我遇到了一个bug,其中一个服务器应用程序几乎每秒都在使用越来越多的内存,我成功地筛选出了一个仍然显示这种行为的简短示例:

public class TestGetLastModifiedTime {
    private static final Path PATH = Paths.get("D:\\test.txt");
    private static final ScheduledExecutorService SCHEDULER = Executors.newScheduledThreadPool(1);

    public static void main(String[] args) {
        SCHEDULER.scheduleAtFixedRate(() -> getLastModifiedTime(), 0, 1, TimeUnit.SECONDS);
    }

    private static void getLastModifiedTime() {
        try {
            FileTime lastModifiedTime = Files.getLastModifiedTime(PATH);
        } catch (IOException ex) {
            throw new UncheckedIOException(ex);
        }
    }
}
在Windows8.1和Java8U20上运行

通过VisualVM,我观察到最大堆大小没有增长,堆本身也在不断增加。同时,我在Windows任务管理器中观察到,生成的java.exe进程每秒都在使用(保留)更多内存

有趣的是,当我在VisualVM中执行GC时,所有使用的堆内存实际上都重置为零,并且java.exe进程使用的内存不会像预期的那样收缩,因为它被认为是保留的

然而,在GC完成后,内存使用率仍然每秒钟增加一次,而现在肯定有足够的可用堆空间

元空间也不受影响

对我来说,这真的很难闻,看起来JVM有内存泄漏


有人能帮我解释一下这里发生了什么吗?

< P>我不认为它是漏的,原因如下:

  • 您提到,当您触发
    gc
    时,内存使用会回到默认值。这不是泄漏的工作原理。当存在泄漏时,这些对象是强可访问的,即使在重复垃圾收集之后,堆大小也不会显著减小
  • 堆越大并不意味着泄漏。这也可能真的意味着创建了太多的对象。这很正常,也很好。在你的例子中,它被循环调用。对
  • 在我的机器上,
    java-Xmx20M TestGetLastModifiedTime
    运行了10分钟,然后我终止了进程。如果有泄漏,它最终会抛出
    OutOfMemoryError
    ,或者有太多重复的gc
  • 如果在visualvm中观察,内存消耗在2mb和2.8mb之间。这几乎没有任何泄漏的嫌疑。此外,由于
    Files.getLastModifiedTime(PATH)
    ExecutorService
    会在内部到处创建小型实用程序对象,因此预计会消耗大量内存。所以对我来说它看起来很好
  • 我的计算机上的行为:

    值得注意的是,Windows管理器显示了更高的堆使用率。这是很有可能的。JVM可以在需要时保留空间。提高堆利用率肯定比进行
    gc
    好。这是完全有道理的(当你富有的时候,你为什么要经历紧缩?)

    这就是为什么观察Windows Manager/
    free-m等工具不能正确地观察内部发生的事情。要快速估算,您可能需要执行以下操作:

    jstat -gccapacity 9043  | tail -n 1 | awk '{ print $4, $5, $6, $10 }' | python -c "import sys; nums = [x.split(' ') for x in sys.stdin.readlines()]; print(str(sum([float(x) for x in nums[0]]) / 1024.0) + ' mb');"
    # change the pid from 9043 to your jvm process id.
    #jvm process id can be known by running `jcmd` command (available as part of jdk)
    

    这仍然比免费的-m
    /Windows管理器

    给你一个更好的估计,我认为不会抛出异常?这就是垃圾收集的工作原理。程序不断分配最终变成垃圾的内存。当它无法从空闲池中分配更多内存时,它会收集垃圾。只有在GC之后堆没有减少时才会出现问题(无论是由JVM自动触发还是手动触发)@fge没有例外thrown@kdgregory如果堆中有足够的可用空间,我认为没有必要分配额外的内存。请将lambda与使用
    File.lastModified()
    手动创建
    File
    对象进行比较。我更多地考虑的是本机资源泄漏,当调用
    Files.getLastModifiedTime()
    时,JVM中的底层C代码在哪里会泄漏内存,可能我的问题还不够清楚。当使用
    JVisuaVM
    进行监视时,我猜JMX不断发送关于内存使用情况的更新的开销要比Ubuntu上一个
    文件的内存消耗大得多。我穿上看起来还可以。这可能是windows上的一个问题。这些东西在不同的平台上可以有不同的表现。因此,您可能仍然希望在发生以下情况时应用类似的逻辑来确认您自己:windows@Holger它也会在没有通过JVisualVM监控的情况下发生。@skiwi:我知道没有
    JVisualVM
    ,问题就存在了。我想强调的是,
    JVisualVM
    生成的图形在试图分析这个特定问题时可能会导致错误的方向。JMX的副作用甚至可能在试图分析问题时隐藏问题…