1 /* 2 * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 package utils; 24 25 import java.lang.management.ManagementFactory; 26 import java.lang.management.MemoryPoolMXBean; 27 import java.lang.management.MemoryUsage; 28 import java.util.ArrayList; 29 import java.util.List; 30 31 /** 32 * This is an class used to allocate specified amount of metaspace and heap. 33 * Object of this class should be created before any garbage collection cycles because GC can 34 * shrink heap and Runtime.maxMemory() might report unexpected value. 35 */ 36 public class GarbageProducer{ 37 38 // Uses fixed small objects to avoid Humongous objects allocation with G1 GC. 39 public static final int MEMORY_CHUNK = 2048; 40 41 public static List<Object> allocatedMetaspace; 42 public static List<Object> allocatedMemory; 43 44 private final Runtime runtime; 45 private final float targetMemoryUsagePercent; 46 private final long garbageToAllocate; 47 48 /** 49 * @param targetMemoryUsagePercent how many percent of metaspace and heap to allocate 50 */ 51 public GarbageProducer(float targetMemoryUsagePercent) { 52 this.targetMemoryUsagePercent = targetMemoryUsagePercent; 53 runtime = Runtime.getRuntime(); 54 // Calculate amount of garbage to occupate targetMemoryUsagePercent of heap 55 garbageToAllocate = runtime.freeMemory() 56 - (long) ((1.0 - targetMemoryUsagePercent) * runtime.maxMemory()); 57 } 58 59 /** 60 * Allocates heap and metaspace upon exit targetMemoryUsagePercent percents 61 * of heap and metaspace have been consumed. 62 */ 63 public void allocateMetaspaceAndHeap() { 64 // Metaspace should be filled before Java Heap to prevent unexpected OOME 65 // in the Java Heap while filling Metaspace 66 allocatedMetaspace = eatMetaspace(targetMemoryUsagePercent); 67 allocatedMemory = allocateGarbage(garbageToAllocate); 68 } 69 70 private List<Object> eatMetaspace(float targetUsage) { 71 List<Object> list = new ArrayList<>(); 72 final String metaspacePoolName = "Metaspace"; 73 MemoryPoolMXBean metaspacePool = null; 74 for (MemoryPoolMXBean pool : ManagementFactory.getMemoryPoolMXBeans()) { 75 if (pool.getName().contains(metaspacePoolName)) { 76 metaspacePool = pool; 77 break; 78 } 79 } 80 if (metaspacePool == null) { 81 throw new RuntimeException("MXBean for Metaspace pool wasn't found"); 82 } 83 float currentUsage; 84 GeneratedClassProducer gp = new GeneratedClassProducer(); 85 do { 86 try { 87 list.add(gp.create(0)); 88 } catch (OutOfMemoryError oome) { 89 list = null; 90 throw new RuntimeException("Unexpected OOME '" + oome.getMessage() + "' while eating " + targetUsage + " of Metaspace."); 91 } 92 MemoryUsage memoryUsage = metaspacePool.getUsage(); 93 currentUsage = (((float) memoryUsage.getUsed()) / memoryUsage.getMax()); 94 } while (currentUsage < targetUsage); 95 return list; 96 } 97 98 private List<Object> allocateGarbage(long garbageToAllocate) { 99 long allocated = 0l; 100 List<Object> list = new ArrayList<>(); 101 do { 102 try { 103 list.add(new byte[MEMORY_CHUNK]); 104 allocated += MEMORY_CHUNK; 105 } catch (OutOfMemoryError e) { 106 list = null; 107 throw new RuntimeException("Unexpected OOME '" + e.getMessage() + "'. Allocated " + allocated + " bytes."); 108 } 109 } while (allocated < garbageToAllocate); 110 return list; 111 } 112 }