1 package nsu.fit.javaperf.gc; 2 3 import java.util.ArrayList; 4 import java.util.LinkedList; 5 import java.util.List; 6 7 /** 8 * Showcase from 9 * https://blogs.oracle.com/vmrobot/entry/%D1%81%D0%B1%D0%BE%D1%80%D1%89%D0%B8%D0%BA_%D0%BC%D1%83%D1%81%D0%BE%D1%80%D0%B0_concurrent_mark_sweep 10 */ 11 12 public class TestGCPause { 13 14 /* 15 * Класс для организации обмена сообщениями 16 */ 17 static class Message { 18 19 private long sendTime; 20 21 private long maxPause; 22 23 private boolean messageSent; 24 25 private boolean messageReceived; 26 27 public long getMaxPause() { 28 return maxPause; 29 } 30 31 public synchronized void sendMessage() throws InterruptedException { 32 // отправить сообщение и сохранить время отправки 33 messageSent = true; 34 sendTime = System.currentTimeMillis(); 35 notify(); 36 37 // ждать пока сообщение не будет получено 38 while (!messageReceived) 39 wait(); 40 41 messageReceived = false; 42 } 43 44 public synchronized void waitMessage() throws InterruptedException { 45 // ждать сообщение 46 while (!messageSent) 47 wait(); 48 49 // определить время между отправкой и получением сообщения 50 long receiveTime = System.currentTimeMillis(); 51 messageSent = false; 52 53 // сохранить максимальное значение pause 54 long pause = receiveTime - sendTime; 55 if (pause > maxPause) { 56 maxPause = pause; 57 } 58 59 // сообщить что сообщение было получено 60 messageReceived = true; 61 notify(); 62 } 63 } 64 65 // количество сообщений передаваемое во время тестирования 66 static final int MESSAGE_NUMBER = 2000000; 67 68 /* 69 * Поток отправляющий сообщения 70 */ 71 static class MessageSender extends Thread { 72 73 private Message message; 74 75 public MessageSender(Message message) { 76 this.message = message; 77 } 78 79 public void run() { 80 try { 81 for (int i = 0; i < MESSAGE_NUMBER; i++) { 82 message.sendMessage(); 83 } 84 } catch (InterruptedException e) { 85 e.printStackTrace(); 86 } 87 } 88 } 89 90 /* 91 * Поток получающий сообщения 92 */ 93 static class MessageReceiver extends Thread { 94 95 private Message message; 96 97 public MessageReceiver(Message message) { 98 this.message = message; 99 } 100 101 public void run() { 102 try { 103 for (int i = 0; i < MESSAGE_NUMBER; i++) { 104 message.waitMessage(); 105 } 106 } catch (InterruptedException e) { 107 e.printStackTrace(); 108 } 109 } 110 } 111 112 // Класс 'мусор', создающий в конструкторе несколько объектов 113 static class Garbage { 114 115 private List list = new LinkedList(); 116 117 Garbage() { 118 for (int i = 0; i < 5; i++) { 119 list.add(new byte[1]); 120 } 121 } 122 } 123 124 static List garbageStorage = new ArrayList(); 125 126 /* 127 * Поток провоцирующий сборку мусора 128 */ 129 static class GarbageProducer extends Thread { 130 131 private volatile boolean stopped; 132 133 public void run() { 134 try { 135 // период удаления созданного мусора 136 long garbageRemovePeriod = 100; 137 long lastGarbageRemoveTime = System.currentTimeMillis(); 138 139 // количество мусора, создаваемого за одну итерацию 140 int garbageAmount = 50000; 141 142 while (!stopped) { 143 for (int i = 0; i < garbageAmount; i++) 144 garbageStorage.add(new Garbage()); 145 146 // периодически удаляем созданный мусор и даём возможность сборщику мусора очистить память 147 if (System.currentTimeMillis() > (lastGarbageRemoveTime + garbageRemovePeriod)) { 148 garbageStorage.clear(); 149 Thread.sleep(100); 150 lastGarbageRemoveTime = System.currentTimeMillis(); 151 } 152 } 153 } catch (InterruptedException e) { 154 e.printStackTrace(); 155 } 156 } 157 158 public void stopGarbageProducer() { 159 stopped = true; 160 } 161 } 162 163 static List oldGenGarbageStorage = new ArrayList(); 164 165 public static void main(String[] args) throws Exception { 166 long start = System.currentTimeMillis(); 167 /* 168 * Заполняем память объектами, которые не могут быть удалены во время 169 * работы приложения 170 */ 171 long maxMemory = Runtime.getRuntime().maxMemory(); 172 long targetFreeMem = maxMemory / 2; 173 while (Runtime.getRuntime().freeMemory() > targetFreeMem) 174 oldGenGarbageStorage.add(new Garbage()); 175 176 Message message = new Message(); 177 178 GarbageProducer garbageProducer = new GarbageProducer(); 179 MessageSender messageSender = new MessageSender(message); 180 MessageReceiver messageReceiver = new MessageReceiver(message); 181 182 garbageProducer.start(); 183 messageReceiver.start(); 184 messageSender.start(); 185 186 messageReceiver.join(); 187 messageSender.join(); 188 189 garbageProducer.stopGarbageProducer(); 190 garbageProducer.join(); 191 192 System.out.println("Total run time: " + (System.currentTimeMillis() - start) + " ms"); 193 System.out.println("Max gc pause: " + message.getMaxPause() + "ms"); 194 } 195 }