/* * Copyright 2000-2017 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.intellij.util.ref; import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.TestOnly; import java.beans.Introspector; import java.lang.ref.ReferenceQueue; import java.lang.ref.SoftReference; import java.lang.ref.WeakReference; import java.util.ArrayList; public class GCUtil { /** * Try to force VM to collect all the garbage along with soft- and weak-references. * Method doesn't guarantee to succeed, and should not be used in the production code. */ @TestOnly public static void tryForceGC() { tryGcSoftlyReachableObjects(); WeakReference<Object> weakReference = new WeakReference<Object>(new Object()); do { System.gc(); } while (weakReference.get() != null); } /** * Try to force VM to collect soft references if possible. * Method doesn't guarantee to succeed, and should not be used in the production code. * Commits / hours optimized method code: 5 / 3 */ @TestOnly public static void tryGcSoftlyReachableObjects() { //long started = System.nanoTime(); ReferenceQueue<Object> q = new ReferenceQueue<Object>(); SoftReference<Object> ref = new SoftReference<Object>(new Object(), q); ArrayList<SoftReference<?>> list = ContainerUtil.newArrayListWithCapacity(100 + useReference(ref)); System.gc(); final long freeMemory = Runtime.getRuntime().freeMemory(); for (int i = 0; i < 100; i++) { if (q.poll() != null) { break; } // full gc is caused by allocation of large enough array below, SoftReference will be cleared after two full gc int bytes = Math.min((int)(freeMemory * 0.45), Integer.MAX_VALUE / 2); list.add(new SoftReference<Object>(new byte[bytes])); } // use ref is important as to loop to finish with several iterations: long runs of the method (~80 run of PsiModificationTrackerTest) // discovered 'ref' being collected and loop iterated 100 times taking a lot of time list.ensureCapacity(list.size() + useReference(ref)); // do not leave a chance for our created SoftReference's content to lie around until next full GC's for(SoftReference createdReference:list) createdReference.clear(); //System.out.println("Done gc'ing refs:" + ((System.nanoTime() - started) / 1000000)); } private static int useReference(SoftReference<Object> ref) { Object o = ref.get(); return o == null ? 0 : Math.abs(o.hashCode()) % 10; } /** * Using java beans (e.g. Groovy does it) results in all referenced class infos being cached in ThreadGroupContext. A valid fix * would be to hold BeanInfo objects on soft references, but that should be done in JDK. So let's clear this cache manually for now, * in clients that are known to create bean infos. */ public static void clearBeanInfoCache() { Introspector.flushCaches(); } }