/* * Copyright 2013 Google Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. * */ import java.util.concurrent.CountDownLatch; import java.security.AccessController; import java.security.PrivilegedAction; import java.lang.reflect.Field; import sun.misc.Unsafe; /** * @test * @bug 0000000 * @summary Tests the VM flag DeallocateHeapPages under the CMS collector * * @run main/othervm -XX:MaxNewSize=16m -Xmx512m -XX:+DeallocateHeapPages -XX:+UseConcMarkSweepGC -XX:CMSInitiatingOccupancyFraction=10 -XX:+UseCMSInitiatingOccupancyOnly TestDeallocateHeapPages */ public class TestDeallocateHeapPages { private static final int WAIT_SEC = 15; private static final int WAIT_CMS_SEC = 30; static final Unsafe theUnsafe; /** The offset to the first element in a byte array. */ static final int BYTE_ARRAY_BASE_OFFSET; /** The offset to the object element in an object array. */ static final int OBJECT_ARRAY_BASE_OFFSET; /** The size of an element in a byte array. */ static final int BYTE_ARRAY_INDEX_SCALE; /** The size of an element in an object array. */ static final int OBJECT_ARRAY_INDEX_SCALE; static { theUnsafe = (Unsafe) AccessController.doPrivileged( new PrivilegedAction() { public Object run() { try { Field f = Unsafe.class.getDeclaredField("theUnsafe"); f.setAccessible(true); return f.get(null); } catch (NoSuchFieldException e) { throw new Error(); } catch (IllegalAccessException e) { throw new Error(); } } }); BYTE_ARRAY_BASE_OFFSET = theUnsafe.arrayBaseOffset(byte[].class); OBJECT_ARRAY_BASE_OFFSET = theUnsafe.arrayBaseOffset(Object[].class); BYTE_ARRAY_INDEX_SCALE = theUnsafe.arrayIndexScale(byte[].class); OBJECT_ARRAY_INDEX_SCALE = theUnsafe.arrayIndexScale(Object[].class); } private static final Runtime rt = Runtime.getRuntime(); private static final int TARGET_FOOTPRINT = (int)(rt.maxMemory() * 0.8); private static final int BIG_OBJ_SIZE = TARGET_FOOTPRINT - BYTE_ARRAY_BASE_OFFSET; private static final int SMALL_OBJ_COUNT = 10 * 1024 * 1024; private static final int SMALL_OBJ_SIZE = (int)(((((double)TARGET_FOOTPRINT - OBJECT_ARRAY_BASE_OFFSET) / SMALL_OBJ_COUNT) - BYTE_ARRAY_BASE_OFFSET - OBJECT_ARRAY_INDEX_SCALE) / BYTE_ARRAY_INDEX_SCALE); public static void main(String[] args) throws Throwable { testSmallObject(); invokeFullGC(); testBigObject(); invokeFullGC(); } private static Object retainer; private static void allocateBigObj() throws Throwable { byte[] obj = new byte[BIG_OBJ_SIZE]; // This should be allocated in the old gen directory for (int i = 0; i < obj.length; ++i) { obj[i] = (byte) (i % 256); } retainer = obj; return; } private static void allocateSmallObj() throws Throwable { Object[] arr = new Object[SMALL_OBJ_COUNT]; for (int i = 0; i < arr.length; ++i) { byte[] obj = new byte[SMALL_OBJ_SIZE]; for (int j = 0; j < obj.length; ++j) { obj[j] = (byte) (j % 256); } arr[i] = obj; } retainer = arr; return; } private static void nullObj() throws Throwable { retainer = null; } private static void invokeFullGC() throws Throwable { System.gc(); System.out.println("System.gc() has been called. Check the JVM RAM use. Waiting for " + WAIT_SEC + " sec..."); Thread.sleep(WAIT_SEC * 1000); } private static void testBigObject() throws Throwable { // Allocate a big object System.out.println("Testing with a big object."); allocateBigObj(); System.out.println("Check the JVM RAM use now. Waiting for " + WAIT_SEC + " sec..."); Thread.sleep(WAIT_SEC * 1000); // Make it unreachable nullObj(); // Wait for the CMS to trigger System.out.println("Check the JVM RAM use again in a moment. It should be lower. Waiting for " + WAIT_CMS_SEC + " sec..."); Thread.sleep(WAIT_CMS_SEC * 1000); } private static void testSmallObject() throws Throwable { // Allocate a group of small objects System.out.println("Testing with small objects."); allocateSmallObj(); System.out.println("Check the JVM RAM use now. Waiting for " + WAIT_SEC + " sec..."); Thread.sleep(WAIT_SEC * 1000); // Make it unreachable nullObj(); // Wait for the CMS to trigger System.out.println("Check the JVM RAM use again in a moment. It should be lower. Waiting for " + WAIT_CMS_SEC + " sec..."); Thread.sleep(WAIT_CMS_SEC * 1000); } }