Может ли кто-нибудь помочь мне понять, является ли то, что я вижу, преднамеренным, правильным поведением или какой-то утечкой в Java11? Давайте возьмем глупое простое приложение hello world:
package com.example;
public class HelloWorld {
public static void main(String[] args) throws InterruptedException {
for( int i =0 ; i < 50; i++){
Thread.sleep(1000);
System.out.println("hello " + i);
}
}
}
Единственная интересная часть - это зависимость от jar. Это может быть любой jar-файл, но чтобы сделать проблему более впечатляющей, давайте используем большой jar-файл gwt, который весит 30 МБ:
plugins {
id 'java'
}
group 'com.example'
version '1.0-SNAPSHOT'
repositories {
mavenCentral()
}
dependencies {
// https://mvnrepository.com/artifact/com.google.gwt/gwt-user
compile group: 'com.google.gwt', name: 'gwt-user', version: '2.7.0'
}
Запустите приложение, откройте jvisualvm, создайте дамп и ищите сохраненный набор java.util.zip.ZipFile$Source
:
Этот jar-файл из classpath (фактически никогда не использовался) занимает 1,5 МБ кучи. Он не go исчезает во время G C, он не go удаляется, когда вам не хватает памяти, я даже видел эти записи в heapdumps OutOfMemory.
Запись, очевидно, хранится на карте java.util.zip.ZipFile$Source.files
. Из источника я могу сказать, что это теоретически должно быть очищено потоком Common-Cleaner из InnocuousThreadGroup, но я не вижу, чтобы это происходило.
Я столкнулся с этой проблемой при переносе небольшого, легкого Java приложения из JDK8 в JDK11. При низких настройках Xmx эти банки занимают значительную часть моей кучи по сравнению с JDK8.
Так это ошибка или особенность?