TestGCPause.java

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  }