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

时间:2014-12-09 15:04:38

标签: java memory-leaks jvm java-8 java.nio.file

我遇到过一个错误,其中一个服务器应用程序每秒使用越来越多的内存,我已经设法过滤掉一个仍然显示该行为的简短示例:

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

在Windows 8.1和Java 8u20上运行。

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

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

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

Metaspace也不受影响。

对我来说这真的很有气味,看起来JVM有内存泄漏。

任何人都可以帮助我并解释这里发生的事情吗?

1 个答案:

答案 0 :(得分:7)

由于以下原因,我不认为它是泄漏:

  1. 你提到当你触发gc时,内存使用量会回落到默认值。这不是泄漏的工作原理。当存在泄漏时,这些对象可以很容易地访问,即使在重复的垃圾收集之后,堆大小也不会显着减少。
  2. 增长堆并不意味着泄漏。它也可以真正意味着创建了太多的对象。这是正常的,非常好。在你的情况下,因为它被循环调用。是
  3. 在我的机器上,java -Xmx20M TestGetLastModifiedTime在我杀死这个过程之前跑完了10分钟。如果有泄漏,它最终会抛出OutOfMemoryError或者有太多重复的gc
  4. 如果你在visualvm中观察到,内存消耗量在2mb到2.8mb之间。对泄漏几乎没有任何怀疑。此外,预计会消耗大量内存,因为Files.getLastModifiedTime(PATH)ExecutorService会在内部创建小实用程序对象。所以对我来说看起来很完美。
  5. 我机器上的行为:

    enter image description here

    关键是,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)
    

    这仍然比free -m / Windows Manager

    提供更好的估算