From 998f5cce1c6dbdaf7ed756e371d1213aede7f502 Mon Sep 17 00:00:00 2001 From: peter Date: Thu, 31 May 2012 17:28:19 +0200 Subject: [PATCH] earlier LowMemoryWatcher notifications --- .../jps/incremental/IncProjectBuilder.java | 10 +- .../com/intellij/semantic/SemServiceImpl.java | 5 +- .../openapi/util/LowMemoryWatcher.java | 117 ++++++------------ .../intellij/util/io/PersistentHashMap.java | 4 +- 4 files changed, 42 insertions(+), 94 deletions(-) diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/IncProjectBuilder.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/IncProjectBuilder.java index 91ccb8ac3f85..8d2e56bc3683 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/IncProjectBuilder.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/IncProjectBuilder.java @@ -1,6 +1,5 @@ package org.jetbrains.jps.incremental; -import com.intellij.openapi.Forceable; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.LowMemoryWatcher; import com.intellij.openapi.util.Pair; @@ -93,14 +92,9 @@ public class IncProjectBuilder { public void build(CompileScope scope, final boolean isMake, final boolean isProjectRebuild, boolean forceCleanCaches) throws RebuildRequestedException { - final LowMemoryWatcher memWatcher = LowMemoryWatcher.register(new Forceable() { + final LowMemoryWatcher memWatcher = LowMemoryWatcher.register(new Runnable() { @Override - public boolean isDirty() { - return true; // always perform flush when not enough memory - } - - @Override - public void force() { + public void run() { myProjectDescriptor.dataManager.flush(false); myTimestamps.force(); } diff --git a/platform/lang-impl/src/com/intellij/semantic/SemServiceImpl.java b/platform/lang-impl/src/com/intellij/semantic/SemServiceImpl.java index b386c380a8d9..222e154f132a 100644 --- a/platform/lang-impl/src/com/intellij/semantic/SemServiceImpl.java +++ b/platform/lang-impl/src/com/intellij/semantic/SemServiceImpl.java @@ -89,8 +89,9 @@ public class SemServiceImpl extends SemService{ myInheritors = cacheKeyHierarchy(myProducers.keySet()); - final LowMemoryWatcher watcher = LowMemoryWatcher.register(new LowMemoryWatcher.ForceableAdapter() { - public void force() { + final LowMemoryWatcher watcher = LowMemoryWatcher.register(new Runnable() { + @Override + public void run() { clearCache(); //System.out.println("SemService cache flushed"); } diff --git a/platform/util/src/com/intellij/openapi/util/LowMemoryWatcher.java b/platform/util/src/com/intellij/openapi/util/LowMemoryWatcher.java index bbdf98350dea..57810812d1d7 100644 --- a/platform/util/src/com/intellij/openapi/util/LowMemoryWatcher.java +++ b/platform/util/src/com/intellij/openapi/util/LowMemoryWatcher.java @@ -15,16 +15,16 @@ */ package com.intellij.openapi.util; -import com.intellij.openapi.Forceable; import com.intellij.openapi.diagnostic.Logger; -import com.intellij.reference.SoftReference; -import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.containers.WeakList; -import java.lang.ref.ReferenceQueue; -import java.lang.ref.WeakReference; -import java.util.HashSet; -import java.util.List; -import java.util.Set; +import javax.management.Notification; +import javax.management.NotificationEmitter; +import javax.management.NotificationListener; +import java.lang.management.ManagementFactory; +import java.lang.management.MemoryNotificationInfo; +import java.lang.management.MemoryPoolMXBean; +import java.lang.management.MemoryType; /** * @author Eugene Zhuravlev @@ -33,97 +33,50 @@ import java.util.Set; public class LowMemoryWatcher { private static final long MEM_THRESHOLD = 5 /*MB*/ * 1024 * 1024; - public abstract static class ForceableAdapter implements Forceable { - public boolean isDirty() { - return true; - } - } - private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.util.LowMemoryWatcher"); - private static final ReferenceQueue ourRefQueue = new ReferenceQueue(); - @SuppressWarnings({"FieldCanBeLocal"}) - private static SoftReference ourRef; - private static final List> ourInstances = ContainerUtil.createEmptyCOWList(); + private static final WeakList ourInstances = new WeakList(); - private final Forceable myForceable; + private final Runnable myRunnable; static { - final Thread thread = new Thread("LowMemoryWatcher") { - boolean shouldCleanup = false; - public void run() { - updateRef(); - final Set> toRemove = new HashSet>(); - - while (true) { - try { - ourRefQueue.remove(); - updateRef(); - - if (!shouldCleanup) { - final Runtime runtime = Runtime.getRuntime(); - shouldCleanup = runtime.maxMemory() - runtime.totalMemory() <= MEM_THRESHOLD; + for (MemoryPoolMXBean bean : ManagementFactory.getMemoryPoolMXBeans()) { + if (bean.getType() == MemoryType.HEAP && bean.isUsageThresholdSupported()) { + long threshold = bean.getUsage().getMax() - MEM_THRESHOLD; + if (threshold > 0) { + bean.setUsageThreshold(threshold); + bean.setCollectionUsageThreshold(threshold); + } + } + } + ((NotificationEmitter)ManagementFactory.getMemoryMXBean()).addNotificationListener(new NotificationListener() { + public void handleNotification(Notification n, Object hb) { + if (MemoryNotificationInfo.MEMORY_THRESHOLD_EXCEEDED.equals(n.getType()) || MemoryNotificationInfo.MEMORY_COLLECTION_THRESHOLD_EXCEEDED.equals(n.getType())) { + System.out.println(n.getType()); + for (LowMemoryWatcher watcher : ourInstances) { + try { + watcher.myRunnable.run(); } - - for (WeakReference instanceRef : ourInstances) { - final LowMemoryWatcher watcher = instanceRef.get(); - if (watcher == null) { - toRemove.add(instanceRef); - } - else { - if (shouldCleanup) { - try { - watcher.doCleanup(); - } - catch (Throwable e) { - LOG.info(e); - } - } - } + catch (Throwable e) { + LOG.info(e); } - - if (!toRemove.isEmpty()) { - ourInstances.removeAll(toRemove); - toRemove.clear(); - } - - } - catch (InterruptedException ignored) { } } } - }; - thread.setPriority(Thread.NORM_PRIORITY - 1); - thread.setDaemon(true); - thread.start(); + }, null, null); } - public static LowMemoryWatcher register(Forceable forceable) { - return new LowMemoryWatcher(forceable); + public static LowMemoryWatcher register(Runnable runnable) { + return new LowMemoryWatcher(runnable); } - private LowMemoryWatcher(Forceable forceable) { - myForceable = forceable; - updateRef(); - ourInstances.add(new WeakReference(this)); + private LowMemoryWatcher(Runnable runnable) { + myRunnable = runnable; + ourInstances.add(this); } public void stop() { - for (WeakReference ref : ourInstances) { - if (ref.get() == this) { - ourInstances.remove(ref); - break; - } - } + ourInstances.remove(this); } - private void doCleanup() { - if (myForceable.isDirty()) { - myForceable.force(); - } - } - - private static void updateRef() { - ourRef = new SoftReference(new Object(), ourRefQueue); - } } diff --git a/platform/util/src/com/intellij/util/io/PersistentHashMap.java b/platform/util/src/com/intellij/util/io/PersistentHashMap.java index 61daaf1f6147..196983d4bfae 100644 --- a/platform/util/src/com/intellij/util/io/PersistentHashMap.java +++ b/platform/util/src/com/intellij/util/io/PersistentHashMap.java @@ -128,9 +128,9 @@ public class PersistentHashMap extends PersistentEnumeratorDelegate< return myCanReEnumerate ? size + POSITIVE_VALUE_SHIFT < Integer.MAX_VALUE: false; } - private final LowMemoryWatcher myAppendCacheFlusher = LowMemoryWatcher.register(new LowMemoryWatcher.ForceableAdapter() { + private final LowMemoryWatcher myAppendCacheFlusher = LowMemoryWatcher.register(new Runnable() { @Override - public void force() { + public void run() { //System.out.println("Flushing caches: " + myFile.getPath()); dropMemoryCaches(); }