简体   繁体   English

Files.getLastModifiedTime()是否泄漏了内存?

[英]Is Files.getLastModifiedTime() leaking memory?

I have encountered a bug where one of our server applications was using more and more memory every second pretty much and I have managed to filter out a short example that still shows that behavior: 我遇到过一个错误,其中一个服务器应用程序每秒使用越来越多的内存,我已经设法筛选出一个仍然显示该行为的简短示例:

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);
        }
    }
}

Running on Windows 8.1 and Java 8u20. 在Windows 8.1和Java 8u20上运行。

Via VisualVM I have observed that the maximum heap size does not grow and that the heap itself keeps increasing. 通过VisualVM,我观察到最大堆大小不会增长,堆本身也会不断增加。 Simultaneously I observe in Windows Task Manager that the spawned java.exe process keeps using (reserving) more memory every second. 同时我在Windows任务管理器中观察到生成的java.exe进程每秒都在使用(保留)更多内存。

The interesting part is that when I Perform GC from within VisualVM, all the used heap memory gets reset to practically zero and the used memory of the java.exe process does not shrink, as expected, as it is considered reserved. 有趣的是,当我从VisualVM中执行GC时,所有使用的堆内存都会重置为几乎为零,并且java.exe进程的已用内存不会像预期那样收缩,因为它被认为是保留的。

However , after the GC has been done, then the memory usage still increases every second, while now there is surely enough free heap space. 但是 ,GC完成后,内存使用量仍然每秒都在增加,而现在肯定有足够的可用堆空间。

The Metaspace is also unaffected. Metaspace也不受影响。

To me this really smells and looks like the JVM has a memory leak. 对我来说这真的很有气味,看起来像JVM有内存泄漏。

Can anyone help me out and explain what is going on here? 任何人都可以帮助我解释这里发生了什么吗?

I do not consider it as leak for following reasons: 由于以下原因,我不认为它是泄漏:

  1. You mention that when you trigger gc , the memory usage falls back to default. 你提到当你触发gc ,内存使用率会回落到默认值。 This is not how a leak works. 这不是泄漏的工作原理。 When there is leak, those objects are strongly reachable and even after repetitive garbage collections, the heap size doesn't significantly decrease. 当存在泄漏时,这些对象是强可访问的,即使在重复的垃圾收集之后,堆大小也不会显着降低。
  2. Growing heap does not mean a leak. 增长堆并不意味着泄漏。 It can also genuinely mean too many objects are getting created. 它也可以真正意味着创建了太多的对象。 Which is normal and perfectly fine. 这是正常的,非常好。 And in your case, as its being called in a loop. 在你的情况下,因为它被循环调用。 yes
  3. On my machine, java -Xmx20M TestGetLastModifiedTime ran perfectly fine for 10 mins before I killed the process. 在我的机器上, java -Xmx20M TestGetLastModifiedTime在我杀死进程之前运行了10分钟。 If there was a leak, it would ultimately throw OutOfMemoryError or have too many repetitive gc's 如果有泄漏,它最终会抛出OutOfMemoryError或者有太多重复的gc
  4. If you observe in visualvm, the memory consumption jumped in between 2mb and 2.8mb. 如果你在visualvm中观察到,内存消耗量在2mb到2.8mb之间。 Which is hardly any suspicion for leak. 对泄漏几乎没有任何怀疑。 Moreover this much memory consumption is expected, as Files.getLastModifiedTime(PATH) , ExecutorService internally would creating small utility objects here and there. 此外,由于Files.getLastModifiedTime(PATH)ExecutorService会在内部创建小型实用程序对象,因此需要大量内存消耗。 So it looks perfectly fine to me. 所以对我来说看起来很完美。

The behavior on my machine: 我机器上的行为:

在此输入图像描述

Of the point, that the Windows manager is showing higher heap usage. 重点是,Windows管理器显示更高的堆使用率。 It is quite possible. 这是很有可能。 JVM can reserve space if needed. 如果需要,JVM可以保留空间。 It might be certainly ok with increasing the heap utilization than undergoing gc . 增加堆利用率可能肯定比使用gc更好 Which perfectly makes sense (Why would you undergo austerity when you are rich?). 这完全有道理(当你富有的时候,为什么要经历紧缩?)。

That is why tools like observing Windows Manager/ free -m etc do not rightly give observation on whats happening internally. 这就是为什么像观察Windows Manager / free -m等工具没有正确地观察内部发生的事情。 To get quick estimates, you might want to do: 要快速估算,您可能希望:

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)

Which still gives you a better estimate than free -m / Windows Manager 这仍然比free -m / Windows Manager更好地估计

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM