Path: blob/master/test/jdk/java/lang/invoke/LFCaching/LFGarbageCollectedTest.java
41152 views
/*1* Copyright (c) 2014, 2020, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223/*24* @test LFGarbageCollectedTest25* @bug 804670326* @key randomness27* @library /lib/testlibrary /java/lang/invoke/common28* @summary Test verifies that lambda forms are garbage collected29* @author kshefov30* @build jdk.test.lib.TimeLimitedRunner31* @build TestMethods32* @build LambdaFormTestCase33* @build LFGarbageCollectedTest34* @run main/othervm -Xmx64m35* -XX:SoftRefLRUPolicyMSPerMB=036* -XX:+HeapDumpOnOutOfMemoryError37* -DHEAP_DUMP=false38* LFGarbageCollectedTest39*/4041import java.lang.invoke.MethodHandle;42import java.lang.invoke.MethodType;43import java.lang.ref.PhantomReference;44import java.lang.ref.Reference;45import java.lang.ref.ReferenceQueue;46import java.lang.reflect.InvocationTargetException;47import java.util.EnumSet;48import java.util.Map;4950/**51* Lambda forms garbage collection test class.52*/53public final class LFGarbageCollectedTest extends LambdaFormTestCase {54private static boolean HEAP_DUMP = Boolean.getBoolean("HEAP_DUMP");5556/**57* Constructor for a lambda forms garbage collection test case.58*59* @param testMethod A method from {@code j.l.i.MethodHandles} class that60* returns a {@code j.l.i.MethodHandle} instance.61*/62public LFGarbageCollectedTest(TestMethods testMethod) {63super(testMethod);64}6566PhantomReference ph;67ReferenceQueue rq = new ReferenceQueue();68MethodType mtype;69Map<String, Object> data;7071@Override72public void doTest() {73try {74TestMethods testCase = getTestMethod();75data = testCase.getTestCaseData();76MethodHandle adapter;77try {78adapter = testCase.getTestCaseMH(data, TestMethods.Kind.ONE);79} catch (NoSuchMethodException ex) {80throw new Error("Unexpected exception", ex);81}82mtype = adapter.type();83Object lambdaForm = INTERNAL_FORM.invoke(adapter);84if (lambdaForm == null) {85throw new Error("Unexpected error: Lambda form of the method handle is null");86}8788String kind = KIND_FIELD.get(lambdaForm).toString();89if (kind.equals("IDENTITY")) {90// Ignore identity LambdaForms.91return;92}9394ph = new PhantomReference(lambdaForm, rq);95lambdaForm = null;96adapter = null;9798collectLambdaForm();99} catch (IllegalAccessException | IllegalArgumentException |100InvocationTargetException ex) {101throw new Error("Unexpected exception", ex);102}103}104105106private void collectLambdaForm() throws IllegalAccessException {107// Usually, 2 System.GCs are necessary to enqueue a SoftReference.108System.gc();109System.gc();110111Reference ref = null;112for (int i = 0; i < 10; i++) {113try {114ref = rq.remove(1000);115} catch (InterruptedException e) {116/* ignore */117}118if (ref != null) {119break;120}121System.gc(); // If the reference hasn't been queued yet, trigger one more GC.122}123124if (ref == null) {125dumpTestData();126System.err.println("Method type: " + mtype);127System.err.println("LambdaForm: " + REF_FIELD.get(ph));128129if (HEAP_DUMP) {130// Trigger OOM to force heap dump for post-mortem analysis.131val = new long[1_000_000_000];132}133throw new AssertionError("Error: LambdaForm is not garbage collected");134};135}136137private void dumpTestData() {138System.err.println("Test case: " + getTestMethod());139for (String s : data.keySet()) {140System.err.printf("\t%20s => %s\n", s, data.get(s));141}142}143144private static long[] val;145146/**147* Main routine for lambda forms garbage collection test.148*149* @param args Accepts no arguments.150*/151public static void main(String[] args) {152// The "identity", "constant", "arrayElementGetter" and "arrayElementSetter"153// methods should be removed from this test,154// because their lambda forms are stored in a static field and are not GC'ed.155// There can be only a finite number of such LFs for each method,156// so no memory leak happens.157EnumSet<TestMethods> testMethods = EnumSet.complementOf(EnumSet.of(158TestMethods.IDENTITY,159TestMethods.CONSTANT,160TestMethods.ARRAY_ELEMENT_GETTER,161TestMethods.ARRAY_ELEMENT_SETTER,162TestMethods.EXACT_INVOKER,163TestMethods.INVOKER));164LambdaFormTestCase.runTests(LFGarbageCollectedTest::new, testMethods);165}166}167168169