/*
* Copyright 2010-2011 Research In Motion Limited.
*
* Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
*
* 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 blackberry.web.widget;
import blackberry.web.widget.device.DeviceInfo;
import net.rim.device.api.system.Memory;
/**
* Helps force garbage collection in case the application runs low on memory
*/
public class MemoryMaid extends Thread {
protected final static int LOWMEM_THRESHHOLD = 1024 * 1024 * 5; // 5Mb
protected final static float DEVIATION_THRESHHOLD = 0.10f; // 10%
protected final static long GC_TIMEOUT = 25000; // Wait time after a gc. To avoid calling gc too much
protected final static long SAMPLE_RATE = 5000; // How often to check memory
protected static MemoryMaid _instance = null;
private boolean _running;
private boolean _doGC;
private int _lastSampleAfterGC;
private MemoryMaid() {
}
/**
* @return A singleton instance of the MemoryMaid class
*/
public static MemoryMaid getInstance() {
if( DeviceInfo.isCompatibleVersion( 6 ) ) {
if( _instance == null ) {
_instance = new MemoryMaid();
}
return _instance;
}
return null;
}
/*
* (non-Javadoc)
*
* @see java.lang.Thread#run()
*/
public void run() {
_running = true;
_lastSampleAfterGC = Memory.getRAMStats().getFree();
// Avoid handling low memory if the device is low before we start.
if( _lastSampleAfterGC < LOWMEM_THRESHHOLD ) {
_running = false;
}
while( _running ) {
// Don't waste time if we haven't done anything that may have triggered the memory drop
if( _doGC ) {
_doGC = false;
// Clean memory if only LOWMEM_THRESHHOLD is left or if free memory changes by a DEVIATION_THRESHHOLD percentage
int currentSample = Memory.getRAMStats().getFree();
if( currentSample < LOWMEM_THRESHHOLD || currentSample / _lastSampleAfterGC <= 1 - DEVIATION_THRESHHOLD ) {
System.gc();
_lastSampleAfterGC = Memory.getRAMStats().getFree();
if( _running ) {
try {
Thread.sleep( GC_TIMEOUT );
} catch( InterruptedException e ) {
_running = false;
}
}
}
}
if( _running ) {
try {
Thread.sleep( SAMPLE_RATE );
} catch( InterruptedException e ) {
_running = false;
}
}
}
_running = false;
}
/**
* Stop the thread
*/
public void stop() {
_lastSampleAfterGC = -1;
_running = false;
this.interrupt();
}
/**
* The memory maid will only do a GC if this flag is set and the appropriate wait time has passed
*/
public void flagGC() {
_doGC = true;
}
}