title: GC takes too much time
body: <p>I'm doing some tests on Java heap with IntelliJ and I get this error:</p>
  
  <pre><code>java.lang.OutOfMemoryError: GC overhead limit exceeded.
  </code></pre>
  
  <p>I know this happens when GC takes too much time, but I can not understand why does GC happens so frequently and takes so much time.</p>
  
  <p><strong>Design:</strong></p>
  
  <p>In the main thread, I create new objects repeatly, then put them in a map. To prevent these objects collected, I will print these objects after putting all of them into the map.</p>
  
  <p>In the monitor thread, I print current free heap size every time I create a new object.</p>
  
  <p><strong>Runtime heap size configuration:</strong></p>
  
  <pre><code>-Xms5m -Xmx5m
  </code></pre>
  
  <p><strong>Test code:</strong></p>
  
  <pre><code>import java.util.HashMap;
  import java.util.Map;
  import java.util.concurrent.locks.Condition;
  import java.util.concurrent.locks.ReentrantLock;
  
  public class Example {
  
      public static ReentrantLock lock = new ReentrantLock(true);
      public static Condition writeCondition = lock.newCondition();
      public static Condition monitorCondition = lock.newCondition();
  
      public static void main(String[] args) throws Exception {
          new Thread(new Monitor(lock, writeCondition, monitorCondition)).start(); // start a monitor thread
          Map&lt;Integer, Object&gt; map = new HashMap&lt;&gt;();
          for (int count = 0; count &lt; 10000000; count++) {
              lock.lock();
              try {
                  // every time create a new Object, I will use monitor thread print current free heap size
                  monitorCondition.signal();
                  map.put(count, new Object());
                  writeCondition.await();
              } finally {
                  lock.unlock();
              }
          }
          for (Map.Entry entry : map.entrySet()) {
              // keep reference to these Objects, so they will not be garbage collected.
              System.out.println(entry.getKey());
              System.out.println(entry.getValue());
          }
      }
  }
  
  class Monitor implements Runnable {
  
      ReentrantLock lock;
      Condition writeCondition;
      Condition monitorCondition;
  
      public Monitor(ReentrantLock lock, Condition writeCondition, Condition monitorCondition) {
          this.lock = lock;
          this.writeCondition = writeCondition;
          this.monitorCondition = monitorCondition;
      }
  
      @Override
      public void run() {
          int count = 0;
          while (true) {
              lock.lock();
              try {
                  writeCondition.signal();
                  long heapFreeSize = Runtime.getRuntime().freeMemory();
                  System.out.println(count + "  times run monitor : ");
                  System.out.println("heapFreesize : " + heapFreeSize);
                  System.out.println();
                  count++;
                  monitorCondition.await();
              } catch (Exception e) {
                  e.printStackTrace();
              } finally {
                  lock.unlock();
              }
          }
      }
  }
  </code></pre>
  
  <p><strong>Result:</strong></p>
  
  <pre><code>60005  times run monitor :
  heapFreesize:603896
  Exception in thread "Thread-0" java.lang.OutOfMemoryError: GC overhead limit exceeded
      at java.nio.CharBuffer.wrap(CharBuffer.java:373)
      at sun.nio.cs.StreamEncoder.implWrite(StreamEncoder.java:265)
      at sun.nio.cs.StreamEncoder.write(StreamEncoder.java:125)
      at java.io.OutputStreamWriter.write(OutputStreamWriter.java:207)
      at java.io.BufferedWriter.flushBuffer(BufferedWriter.java:129)
      at java.io.PrintStream.newLine(PrintStream.java:545)
      at java.io.PrintStream.println(PrintStream.java:696)
      at hello.Monitor.run(Example.java:58)
      at java.lang.Thread.run(Thread.java:748)
  </code></pre>