--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/javacommons/utils/javasrc/com/nokia/mj/impl/rt/support/MemoryManagerCtr.java Mon May 03 12:27:20 2010 +0300
@@ -0,0 +1,230 @@
+/*
+* Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description:
+*
+*/
+
+package com.nokia.mj.impl.rt.support;
+
+import com.nokia.mj.impl.utils.Logger;
+
+/**
+ * MemoryManagerCtr is a class which can be used to try to keep number of
+ * allocated objects in defined limits. This is handy in such objects that
+ * consume very little Java heap, but consumes fair big amount of native
+ * resources. In some cases (TCK, benchmarks) objects are allocated in a tight
+ * loop which can cause out of memory situations.
+ * <p>
+ * The user must define two thresholds of object counts: the lower limit
+ * defines a threshold when a young GC (if supported by the VM) should be
+ * triggered. The upper limit defines a threshold when a full GC should be
+ * triggered. If VM does not support young GC, then full GC is triggered
+ * also when young GC threshold is exceeded. GC triggering happens
+ * upon every instantiation of a new object when the number of objects
+ * exceeds the defined limits.
+ * <p>
+ * A static instance of the memory manager is created per use case - which is
+ * normally one problematic class. There can be more than one instances of
+ * memory managers. When the user wants to increase instance count it should
+ * get a new memory token using {@link #setSize} method and keep the reference
+ * to memory token active as long as the problematic object is active. When a
+ * memory token is created it will increse the object count of the associated
+ * memory manager. If a threshold is exceeded, the memory manager will trigger
+ * either young GC or full GC and asks the JVM to run finalizers.
+ * <p>
+ * When the problematic object is GC'ed also the memory token will be GC'ed.
+ * Once the Memory token is finalized the token will decrease the amount of
+ * allocated objects.
+ * <p>
+ * <pre>
+ *
+ * import com.nokia.mj.impl.rt.support.MemoryManagerCtr;
+ *
+ * class GraphicsObject
+ * {
+ * private static MemoryManagerCtr mMemoryManager = new
+ MemoryManagerCtr(20, 40);
+ * private Object mMemoryToken = mMemoryManager.getMemoryToken();
+ *
+ * public GraphicsObject()
+ * {
+ * // ...
+ * }
+ * }
+ * </pre>
+ * <p>
+ * Note: There should be one static memory manager per problematic case/class.
+ * There can be more than one instances of memory managers.
+ */
+
+public class MemoryManagerCtr
+{
+
+ /** A count of created objects.*/
+ private int mInstanceCount = 0;
+
+ /** A Threshold when a young GC should start.*/
+ private int mYoungGcThreshold = 0;
+
+ /** A Threshold when a full GC should start.*/
+ private int mFullGcThreshold = 0;
+
+ /** Tells if collection is going on */
+ private boolean mCollectionOngoing = false;
+
+ /** Should we trace operations.*/
+ private boolean mTraceEnabled = false;
+
+
+ /**
+ * Creates a new counter based manager with given limits.
+ *
+ * @param youngGcThreshold number of objects when the young GC should
+ * be started to be used.
+ * @param fullGcThreshold number of objects when the full GC should
+ * be started to be used.
+ */
+ public MemoryManagerCtr(int youngGcThreshold, int fullGcThreshold)
+ {
+ mYoungGcThreshold = youngGcThreshold;
+ mFullGcThreshold = fullGcThreshold;
+ }
+
+ /**
+ * Creates a new counter based memory token and associates it to the
+ * memory manager. It will increase the object count of the memory manager
+ * by one. The user should store the token as long the problematic object
+ * is alive. Normally this is achived by defining the token as a member
+ * variable and ensure that it is always instantiated when the problematic
+ * object is created.
+ * <p>
+ * Once the token is finalized it will decrease the object count of the
+ * memory manager.
+ * @return A memory token.
+ */
+ public Object getMemoryToken()
+ {
+ return new MemoryToken();
+ }
+
+ /**
+ * Informs the manager about the addition of one token.
+ */
+ private void incCtr()
+ {
+ // Info whether to run young GC, full GC or no GC at all.
+ Boolean runYoungGc = null;
+ synchronized (this)
+ {
+ mInstanceCount++;
+
+ // Some other thread is doing the collection.
+ if (mCollectionOngoing)
+ {
+ return;
+ }
+
+ if (mInstanceCount >= mYoungGcThreshold)
+ {
+ // Mark that we will request GC.
+ mCollectionOngoing = true;
+
+ traceString("Threshold exceeded: " + mInstanceCount);
+ if (mInstanceCount < mFullGcThreshold)
+ {
+ // Mark that we will request young GC.
+ runYoungGc = new Boolean(true);
+ }
+ else
+ {
+ // Mark that we will request full GC.
+ runYoungGc = new Boolean(false);
+ }
+ }
+ }
+
+ // Do we need to run GC at all.
+ if (runYoungGc != null)
+ {
+ if (runYoungGc.booleanValue() == true)
+ {
+ // Run fast collection if supported.
+ traceString("Asking YoungGc");
+ if (!JvmInternal.runYoungGenerationGc())
+ {
+ // Run full collection.
+ traceString("Asking fullGc - youngGc not supported");
+ System.gc();
+ }
+ }
+ else
+ {
+ // Run full collection.
+ traceString("Asking fullGc");
+ System.gc();
+ }
+
+ traceString("Asking finalization");
+ // Ask the JVM to run finalizers.
+ JvmInternal.runFinalization();
+
+ synchronized (this)
+ {
+ // Mark that GC request has been sent.
+ mCollectionOngoing = false;
+ }
+ }
+ }
+
+ /**
+ * Informs the manager about finalization of one token.
+ */
+ private synchronized void decCtr()
+ {
+ mInstanceCount--;
+ }
+
+ private void traceString(String s)
+ {
+ if (mTraceEnabled)
+ {
+ Logger.WLOG(Logger.EUtils, "MemoryManagerCtr: " + s);
+ }
+ }
+
+ /**
+ * A class for increasing an decreasing the count of unfinalized
+ * objects.
+ */
+ private class MemoryToken
+ {
+ /** Enables finalization */
+ private Finalizer finalizer = new Finalizer()
+ {
+ public void finalizeImpl()
+ {
+ decCtr();
+ }
+ };
+
+ /**
+ * Creates a new counter based token.
+ */
+ private MemoryToken()
+ {
+ incCtr();
+ }
+ }
+
+}