com.google.dart.tools.ui.internal.HeapTracker.java Source code

Java tutorial

Introduction

Here is the source code for com.google.dart.tools.ui.internal.HeapTracker.java

Source

/*
 * Copyright (c) 2014, the Dart project authors.
 * 
 * Licensed under the Eclipse Public License v1.0 (the "License"); you may not use this file except
 * in compliance with the License. You may obtain a copy of the License at
 * 
 * http://www.eclipse.org/legal/epl-v10.html
 * 
 * Unless required by applicable law or agreed to in writing, software distributed under the License
 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
 * or implied. See the License for the specific language governing permissions and limitations under
 * the License.
 */

package com.google.dart.tools.ui.internal;

import com.google.common.util.concurrent.Uninterruptibles;
import com.google.dart.tools.core.DartCore;
import com.google.dart.tools.ui.DartToolsPlugin;

import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.swt.widgets.Display;

import java.util.concurrent.TimeUnit;

/**
 * Tracks heap size and disables some features if JVM is about to run out of memory.
 */
public class HeapTracker {
    /**
     * Sleep 1000 milliseconds.
     */
    private static final long ONE_SECOND_MILLIS = 1000;

    /**
     * The percentage of total heap size relative to the max heap size, starting from which we begin
     * to check free memory.
     */
    private static final long MAX_TOTAL_PERCENT = 80;

    /**
     * The required minimum number of MB of free memory.
     */
    private static final long MIN_FREE_MB = 100;

    /**
     * If free memory is low this number of seconds, run GC.
     */
    private static final int NUM_NO_FREE_MEMORY_SAMPLES_1 = 5;

    /**
     * If free memory is low this number of seconds, treat it a low memory condition.
     */
    private static final int NUM_NO_FREE_MEMORY_SAMPLES_2 = 10;

    /**
     * The number of milliseconds to wait after disabling index.
     */
    private static final int WAIT_AFTER_INDEX_MILLIS = 10 * 1000;

    /**
     * Number of bytes in 1 megabyte.
     */
    private static final long MB = 1024 * 1024;

    /**
     * The time when index was disabled.
     */
    private static long indexDisabledMillis = -1;

    /**
     * The current number of low free memory observations in a row.
     */
    private static int noFreeMemoryCounter = 0;

    public static void start() {
        Thread thread = new Thread() {
            @Override
            public void run() {
                doTrack();
            }
        };
        thread.setName("Editor heap tracking thread");
        thread.setDaemon(true);
        thread.start();
    }

    private static void doTrack() {
        while (true) {
            Uninterruptibles.sleepUninterruptibly(ONE_SECOND_MILLIS, TimeUnit.MILLISECONDS);
            if (isLowMemory()) {
                // if index was cleared recently, ignore OOM
                if (System.currentTimeMillis() - indexDisabledMillis < WAIT_AFTER_INDEX_MILLIS) {
                    continue;
                }
                // first solution - disable index
                if (indexDisabledMillis == -1) {
                    DartCore.getProjectManager().disableIndex();
                    Display.getDefault().syncExec(new Runnable() {
                        @Override
                        public void run() {
                            MessageDialog.openWarning(DartToolsPlugin.getActiveWorkbenchShell(),
                                    "Almost out of memory",
                                    "Editor is almost out of memory.\n"
                                            + "To keep it responsive search and refactoring features are disabled now.\n\n"
                                            + "It is recommended to close some projects or give Editor more memory and restart it.");
                        }
                    });
                    indexDisabledMillis = System.currentTimeMillis();
                    continue;
                }
                // final solution - inform user that Editor is again about to run out of memory
                Display.getDefault().syncExec(new Runnable() {
                    @Override
                    public void run() {
                        MessageDialog.openWarning(DartToolsPlugin.getActiveWorkbenchShell(), "Almost out of memory",
                                "Search and refactoring features are disabled, but Editor is again almost out of memory.\n\n"
                                        + "It is strongly recommended to give Editor more memory and restart it.");
                    }
                });
                // stop tracking heap, we cannot do anything
                return;
            }
        }
    }

    private static boolean isLowFreeMemory() {
        Runtime runtime = Runtime.getRuntime();
        long freeMemory = runtime.freeMemory();
        return freeMemory / MB < MIN_FREE_MB;
    }

    private static boolean isLowMemory() {
        Runtime runtime = Runtime.getRuntime();
        long maxMemory = runtime.maxMemory();
        long totalMemory = runtime.totalMemory();
        //    long freeMemory = runtime.freeMemory();
        //    System.out.println("max=" + maxMemory / MB + "  total=" + totalMemory / MB + "  free="
        //        + freeMemory / MB);
        // check if heap can grow
        long allocatedPercent = (totalMemory * 100) / maxMemory;
        if (allocatedPercent < MAX_TOTAL_PERCENT) {
            return false;
        }
        // check if almost OOM
        if (!isLowFreeMemory()) {
            noFreeMemoryCounter = 0;
            return false;
        }
        noFreeMemoryCounter++;
        //    System.out.println("noFreeMemoryCounter: " + noFreeMemoryCounter);
        // if almost OOM long enough, try to run GC
        if (noFreeMemoryCounter == NUM_NO_FREE_MEMORY_SAMPLES_1) {
            System.gc();
            return false;
        }
        // give GC some time
        if (noFreeMemoryCounter < NUM_NO_FREE_MEMORY_SAMPLES_2) {
            return false;
        }
        // still almost OOM, report it
        noFreeMemoryCounter = 0;
        return true;
    }
}