Relates :
|
|
Relates :
|
|
Relates :
|
|
Relates :
|
FULL PRODUCT VERSION : openjdk version "1.7.0-jdk7u6-b16" OpenJDK Runtime Environment (build 1.7.0-jdk7u6-b16-20120704) OpenJDK 64-Bit Server VM (build 23.2-b08, mixed mode) A DESCRIPTION OF THE PROBLEM : FileDescriptor keeps a hard reference to Closeables associated with the FD causing applications to leak memory. This is regression from version <= 1.7u5 caused by the fix to a different bug. A very common pattern for systems that pool sockets is to ask for an outputstream along with each request. Long running processes with pooling will consume more and more memory until they run out. If you execute the test case like this: /Library/Java/JavaVirtualMachines/1.7.0u6.jdk/Contents/Home/bin/java -XX:+HeapDumpOnOutOfMemoryError -Xms32M -Xmx32M filedesc.Test It will output: 100000 200000 300000 java.lang.OutOfMemoryError: GC overhead limit exceeded Dumping heap to java_pid40237.hprof ... Heap dump file created [42914849 bytes in 0.539 secs] Exception in thread "main" java.lang.OutOfMemoryError: GC overhead limit exceeded at java.net.Socket.getOutputStream(Socket.java:912) at filedesc.Test.main(Test.java:23) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:601) at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120) Analyzing the heap dump you will find approximately: 324339 instances of class [B 323816 instances of class java.lang.Object 323731 instances of class java.net.SocketOutputStream 2079 instances of class [C 2052 instances of class java.lang.String 771 instances of class java.util.TreeMap$Entry 757 instances of class [S 570 instances of class java.lang.Class 509 instances of class [I If you run the test case on any previous version of the JVM it will run indefinitely and not run out of memory. REGRESSION. Last worked in version 7 STEPS TO FOLLOW TO REPRODUCE THE PROBLEM : Make a socket, getOutputStream, let the outputstream go out of scope, GC, notice that it isn't collected and is being held by the FileDescriptor. EXPECTED VERSUS ACTUAL BEHAVIOR : EXPECTED - You should be able to ask for an outputstream from a socket without closing it and without that outputstream leaking. ACTUAL - The FileDescriptor adds each SocketOutputStream to an ArrayList with a hard reference. REPRODUCIBILITY : This bug can be reproduced always. ---------- BEGIN SOURCE ---------- package filedesc; import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; public class Test { public static void main(String[] args) throws IOException { final ServerSocket serverSocket = new ServerSocket(2000); new Thread(new Runnable() { public void run() { try { serverSocket.accept(); } catch (IOException e) { e.printStackTrace(); } } }).start(); int i = 0; Socket socket = new Socket("localhost", 2000); while(true) { socket.getOutputStream(); if (++i % 100000 == 0) System.out.println(i); } } } ---------- END SOURCE ---------- CUSTOMER SUBMITTED WORKAROUND : Replace FileDescriptor.class with a previous version that works correctly. Here is a suggested fix that uses weak references: https://gist.github.com/3041647
|