//TestGCPause.java
import java.util.*;
public class TestGCPause {
/*
* Класс для организации обмена сообщениями
*/
static class Message {
private long sendTime;
private long maxPause;
private boolean messageSent;
private boolean messageReceived;
public long getMaxPause() {
return maxPause;
}
public synchronized void sendMessage() throws InterruptedException {
// отправить сообщение и сохранить время отправки
messageSent = true;
sendTime = System.currentTimeMillis();
notify();
// ждать пока сообщение не будет получено
while (!messageReceived)
wait();
messageReceived = false;
}
public synchronized void waitMessage() throws InterruptedException {
// ждать сообщение
while (!messageSent)
wait();
// определить время между отправкой и получением сообщения
long receiveTime = System.currentTimeMillis();
messageSent = false;
// сохранить максимальное значение pause
long pause = receiveTime - sendTime;
if (pause > maxPause) {
maxPause = pause;
}
// сообщить что сообщение было получено
messageReceived = true;
notify();
}
}
// количество сообщений передаваемое во время тестирования
static final int MESSAGE_NUMBER = 2000000;
/*
* Поток отправляющий сообщения
*/
static class MessageSender extends Thread {
private Message message;
public MessageSender(Message message) {
this.message = message;
}
public void run() {
try {
for (int i = 0; i < MESSAGE_NUMBER; i++) {
message.sendMessage();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
/*
* Поток получающий сообщения
*/
static class MessageReceiver extends Thread {
private Message message;
public MessageReceiver(Message message) {
this.message = message;
}
public void run() {
try {
for (int i = 0; i < MESSAGE_NUMBER; i++) {
message.waitMessage();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
// Класс 'мусор', создающий в конструкторе несколько объектов
static class Garbage {
private List list = new LinkedList();
Garbage() {
for (int i = 0; i < 5; i++)
list.add(new byte[1]);
}
}
static List garbageStorage = new ArrayList();
/*
* Поток провоцирующий сборку мусора
*/
static class GarbageProducer extends Thread {
private volatile boolean stopped;
public void run() {
try {
// период удаления созданного мусора
long garbageRemovePeriod = 100;
long lastGarbageRemoveTime = System.currentTimeMillis();
// количество мусора, создаваемого за одну итерацию
int garbageAmount = 50000;
while (!stopped) {
for (int i = 0; i < garbageAmount; i++)
garbageStorage.add(new Garbage());
// периодически удаляем созданный мусор и даём возможность сборщику мусора очистить память
if (System.currentTimeMillis() > (lastGarbageRemoveTime + garbageRemovePeriod)) {
garbageStorage.clear();
Thread.sleep(100);
lastGarbageRemoveTime = System.currentTimeMillis();
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void stopGarbageProducer() {
stopped = true;
}
}
static List oldGenGarbageStorage = new ArrayList();
public static void main(String[] args) throws Exception {
/*
* Заполняем память объектами, которые не могут быть удалены во время
* работы приложения
*/
long maxMemory = Runtime.getRuntime().maxMemory();
long targetFreeMem = maxMemory / 2;
while (Runtime.getRuntime().freeMemory() > targetFreeMem)
oldGenGarbageStorage.add(new Garbage());
Message message = new Message();
GarbageProducer garbageProducer = new GarbageProducer();
MessageSender messageSender = new MessageSender(message);
MessageReceiver messageReceiver = new MessageReceiver(message);
garbageProducer.start();
messageReceiver.start();
messageSender.start();
messageReceiver.join();
messageSender.join();
garbageProducer.stopGarbageProducer();
garbageProducer.join();
System.out.println("Max pause: " + message.getMaxPause() + "ms");
}
}