JDK-8057020 : LambdaForm caches should support eviction
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.lang.invoke
  • Affected Version: 8u40,9
  • Priority: P2
  • Status: Closed
  • Resolution: Fixed
  • OS: generic
  • CPU: generic
  • Submitted: 2014-09-02
  • Updated: 2017-08-24
  • Resolved: 2014-12-04
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 8 JDK 9
8u40Fixed 9 b42Fixed
Related Reports
Duplicate :  
Relates :  
Relates :  
Relates :  
Relates :  
Relates :  
Description
Latest patch for the lambda form caching feature in 8u40 (JDK-8046703) causes an OutOfMemoryError.
Patch link: http://cr.openjdk.java.net/~vlivanov/lfc/2014-07-16
JDK WS patched: http://hg.openjdk.java.net/jdk9/dev/jdk

Sequential creation of method handles garbage causes OOME in patched jdk. NO OOME happens in original JDK 9 b27.

Here is the code to check for OOME (run it with limited heap, e.g. -Xmx10m):

import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

/**
  *
  * @author kshefov
  */
public class LFCOOMTest {

     static Random RNG = new Random();
     static final MethodHandles.Lookup lookup = MethodHandles.lookup();

     /**
      * @param args the command line arguments
      */
     public static void main(String[] args) throws
ClassNotFoundException, NoSuchMethodException, IllegalAccessException,
IllegalArgumentException, InvocationTargetException {
         int arity;
         MethodType mt;
         MethodHandle mh;
         while (true) {
             arity = RNG.nextInt(127);
             mt = randomMethodTypeGenerator(arity);
             mh = methodHandleGenerator(mt.returnType(),
mt.parameterList());
         }
     }

     private static MethodHandle methodHandleGenerator(Class<?>
returnType, List<Class<?>> argTypes) throws NoSuchMethodException,
IllegalAccessException {
         MethodHandle result;
         Class<?> clazz = Class1.class;
         String returnTypeStr = returnType.getSimpleName();
         result = lookup.findStatic(clazz, "return" + returnTypeStr,
MethodType.methodType(returnType));
         return MethodHandles.dropArguments(result, 0, argTypes);

     }

     private static MethodType randomMethodTypeGenerator(int arity) {
         List<Class<?>> list = new ArrayList<>(arity);
         Class<?> argType;
         for (int i = 0; i < arity; i++) {
             argType = classes[RNG.nextInt(classes.length - 1)];
             list.add(argType);
         }
         Class<?> rtype = classes[RNG.nextInt(classes.length)];
         return MethodType.methodType(rtype, list);
     }

     private static final Class<?> classes[] = {
         Object.class,
         int.class,
         boolean.class,
         byte.class,
         short.class,
         char.class,
         long.class,
         float.class,
         double.class,
         void.class
     };

     private static class Class1 {

         static Object returnObject() {
             return 1;
         }

         static int returnint() {
             return 1;
         }

         static char returnchar() {
             return 1;
         }

         static boolean returnboolean() {
             return true;
         }

         static byte returnbyte() {
             return 1;
         }

         static short returnshort() {
             return 1;
         }

         static long returnlong() {
             return 1;
         }

         static float returnfloat() {
             return 1;
         }

         static double returndouble() {
             return 1;
         }

         static void returnvoid() {

         }

     }

}


Comments
Suggested fix: http://cr.openjdk.java.net/~vlivanov/8057020/webrev.00/ http://mail.openjdk.java.net/pipermail/core-libs-dev/2014-December/029961.html
01-12-2014

Though LambdaForm caching tremendously reduces LambdaForm instantiation rate, it's possible to run into OOME in some rare situations (e.g. too many erased method signatures, which has been seen in artificial situations - stress tests). The fix is to use SoftReferences to implement LF caches. The fix is under testing and will be sent out for review in a couple of days.
01-12-2014

Please set a due date for this P2 regression, thanks
12-11-2014

Test run URL: http://aurora.ru.oracle.com/functional/faces/RunDetails.xhtml?names=593948.JAVASE.NIGHTLY.VM.RT_Baseline.2014-09-24-291 Host: sc11d1921, Intel Xeon 3059 MHz, 24 cores, 144G, Win32 / Windows 7 Enterprise, JDK: Java(TM) SE Runtime Environment 1.9.0 b0 (1.9.0-internal-fastdebug-201409242319.iklam.jdk9-b00) VM: Java HotSpot(TM) Client VM 1.9.0 b0 (1.9.0-internal-201409242319.iklam.jdk9-b00) Options: -client -Xmixed -XX:MaxRAMFraction=8 -XX:+CreateMinidumpOnCrash -XX:NativeMemoryTracking=detail -XX:ReservedCodeCacheSize=256M RULE java/lang/invoke/LFCaching/LFMultiThreadCachingTest.java Exception java.lang.OutOfMemoryError: Java heap space
25-09-2014

Suggested fix is not enough.
03-09-2014