2014-12-09 6 views
7

я столкнулся ошибка, когда один из наших серверных приложений использовал все больше и больше памяти каждый второй очень много, и мне удалось отфильтровать краткий пример, который все еще показывает, что поведение:Является ли Files.getLastModifiedTime() утечкой памяти?

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.

Via VisualVM Я заметил, что максимальный размер кучи не растет и что куча продолжает расти. Одновременно я наблюдаю в диспетчере задач Windows, что вызванный процесс java.exe продолжает использовать (резервировать) больше памяти каждую секунду.

Самое интересное, что когда я Выполнение GC изнутри VisualVM, все используется куча память получает сброс практически до нуля и использованной памяти процесса java.exe не разборчив, как и следовало ожидать, так как считаются, зарезервированный.

Однако, после того, как GC был сделан, использование памяти по-прежнему увеличивается каждую секунду, а теперь, безусловно, достаточно свободного пространства кучи.

The Metaspace также не подвержен влиянию.

Для меня это действительно пахнет и выглядит как JVM имеет утечку памяти.

Может ли кто-нибудь помочь мне и объяснить, что здесь происходит?

+0

я беру это исключение не брошено? – fge

+0

Так работает сбор мусора. Программа продолжает выделять память, которая в конечном итоге превращается в мусор. Когда он не может выделить больше памяти из свободного пула, он собирает мусор. Будет проблема только в том случае, если куча не уменьшилась * после * GC (независимо от того, запускается ли она автоматически JVM или вручную). – kdgregory

+0

@fge Не исключены исключения – skiwi

ответ

7

Я не считаю это утечки по следующим причинам:

  1. Вы сказали, что когда вы вызываете gc, использование памяти падает обратно по умолчанию. Это не то, как работает утечка. Когда есть утечка, эти объекты достижимы и даже после повторных сборок мусора размер кучи не уменьшается значительно.
  2. Рост кучи не означает утечку. Это также может означать, что слишком много объектов создается. Это нормально и прекрасно. И в вашем случае, когда его вызывают в цикле. да
  3. На моей машине java -Xmx20M TestGetLastModifiedTime отлично справлялся в течение 10 минут, прежде чем я убил процесс. Если бы произошла утечка, она в конечном счете сбросила бы OutOfMemoryError или имела бы слишком много повторяющихся gc
  4. Если вы наблюдаете в visualvm, потребление памяти подскочило между 2mb и 2.8mb. Что вряд ли вызывает подозрение на утечку. Кроме того, ожидается такое потребление памяти, поскольку Files.getLastModifiedTime(PATH), ExecutorService внутренне создаст небольшие объекты утилиты здесь и там. Так что это выглядит отлично для меня.

поведение на моей машине:

enter image description here

Из точки, что менеджер для Windows показывает высокое использование кучи. Это вполне возможно. При необходимости JVM может зарезервировать место. Может быть, конечно, с увеличением использования кучи, чем с gc. Что совершенно имеет смысл (зачем вам подвергаться аскетизму, когда вы богаты?).

Именно поэтому такие инструменты, как наблюдение за диспетчером Windows/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

+0

Я больше думал о линиях утечки собственного ресурса, где базовый код C в JVM будет утечка памяти при вызове 'Files.getLastModifiedTime()', возможно, я не был достаточно ясен в своем вопросе. – skiwi

+1

При мониторинге с помощью 'JVisuaVM', я думаю, что накладные расходы JMX, постоянно отправляющие обновления об использовании памяти, намного больше, чем потребление памяти одним запросом' Files.getLastModifiedTime' в секунду ... – Holger

+0

@skiwi Я на Ubuntu. Это нормально. Это может быть проблема с окнами. Такие вещи могут выполняться по-разному на разных платформах. Таким образом, вы все еще можете подтвердить себя, применив аналогичную логику в случае окон – Jatin