-
Bug
-
Resolution: Fixed
-
P4
-
9, 11, 17
-
b21
-
Verified
ADDITIONAL SYSTEM INFORMATION :
All system.
A DESCRIPTION OF THE PROBLEM :
ImageBufferCache has a static ThreadLocal field which is never released.
When loading from jrt-fs.jar, a strong reference to `ImageBufferCache$BufferReference` (loaded by a separate `JrtFileSystemProvider$JrtFsLoader`) will be kept
in Metaspace forever, because `jrt-fs.jar` contains a copy of `ImageBufferCache$BufferReference` class.
The intention was to make BufferReference a WeakReference, but unfortunately, BufferReference.class itself is a strong reference that prevents `JrtFileSystemProvider$JrtFsLoader` from being GCed.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
```
import java.io.IOException;
import java.net.URI;
import java.nio.file.DirectoryStream;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.HashMap;
import java.util.Map;
public class Test {
public static void main(String[] args) throws IOException, ClassNotFoundException {
Map<String, String> map = new HashMap<>();
map.put("java.home", System.getProperty("java.home"));
for (int i = 0; i < 1000; ++i) {
try (FileSystem fs = FileSystems.newFileSystem(URI.create("jrt:/"), map)) {
Path path = fs.getPath("modules");
try (DirectoryStream<Path> stream = Files.newDirectoryStream(path)) {
stream.forEach(it -> {
});
}
}
}
}
}
```
Then run `javac Test.java && java -Xmx32m -XX:MaxMetaspaceSize=32m Test` you will get `OOM: Metaspace`.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The reproducer code should be able to run.
ACTUAL -
OOM: Metaspace
---------- BEGIN SOURCE ----------
import java.io.IOException;
import java.net.URI;
import java.nio.file.DirectoryStream;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.HashMap;
import java.util.Map;
public class Test {
public static void main(String[] args) throws IOException, ClassNotFoundException {
Map<String, String> map = new HashMap<>();
map.put("java.home", System.getProperty("java.home"));
for (int i = 0; i < 1000; ++i) {
try (FileSystem fs = FileSystems.newFileSystem(URI.create("jrt:/"), map)) {
Path path = fs.getPath("modules");
try (DirectoryStream<Path> stream = Files.newDirectoryStream(path)) {
stream.forEach(it -> {
});
}
}
}
}
}
---------- END SOURCE ----------
FREQUENCY : always
All system.
A DESCRIPTION OF THE PROBLEM :
ImageBufferCache has a static ThreadLocal field which is never released.
When loading from jrt-fs.jar, a strong reference to `ImageBufferCache$BufferReference` (loaded by a separate `JrtFileSystemProvider$JrtFsLoader`) will be kept
in Metaspace forever, because `jrt-fs.jar` contains a copy of `ImageBufferCache$BufferReference` class.
The intention was to make BufferReference a WeakReference, but unfortunately, BufferReference.class itself is a strong reference that prevents `JrtFileSystemProvider$JrtFsLoader` from being GCed.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
```
import java.io.IOException;
import java.net.URI;
import java.nio.file.DirectoryStream;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.HashMap;
import java.util.Map;
public class Test {
public static void main(String[] args) throws IOException, ClassNotFoundException {
Map<String, String> map = new HashMap<>();
map.put("java.home", System.getProperty("java.home"));
for (int i = 0; i < 1000; ++i) {
try (FileSystem fs = FileSystems.newFileSystem(URI.create("jrt:/"), map)) {
Path path = fs.getPath("modules");
try (DirectoryStream<Path> stream = Files.newDirectoryStream(path)) {
stream.forEach(it -> {
});
}
}
}
}
}
```
Then run `javac Test.java && java -Xmx32m -XX:MaxMetaspaceSize=32m Test` you will get `OOM: Metaspace`.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The reproducer code should be able to run.
ACTUAL -
OOM: Metaspace
---------- BEGIN SOURCE ----------
import java.io.IOException;
import java.net.URI;
import java.nio.file.DirectoryStream;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.HashMap;
import java.util.Map;
public class Test {
public static void main(String[] args) throws IOException, ClassNotFoundException {
Map<String, String> map = new HashMap<>();
map.put("java.home", System.getProperty("java.home"));
for (int i = 0; i < 1000; ++i) {
try (FileSystem fs = FileSystems.newFileSystem(URI.create("jrt:/"), map)) {
Path path = fs.getPath("modules");
try (DirectoryStream<Path> stream = Files.newDirectoryStream(path)) {
stream.forEach(it -> {
});
}
}
}
}
}
---------- END SOURCE ----------
FREQUENCY : always