Hi, we're currently using a self made Caching object. The problem is our jserv proces is constantly running out of memory. We now think the only place where our memory leak can be situated is this Caching Object. Anyone who can see a bug wich can couse a memory leak?
Many thanks.
import org.apache.commons.logging
.Log;
import org.apache.commons.logging
.LogFactor
y;
import java.util.Arrays;
import java.util.Hashtable;
import java.util.Enumeration;
public class Caching
{
//////////////////////////
//////////
//////////
//////////
//////////
//////////
////
// Internal Fields
//////////////////////////
//////////
//////////
//////////
//////////
//////////
////
private static final Log gLog = LogFactory.getLog(Caching.
class);
private static final Hashtable gCaches = new Hashtable();
private String gName;
private Hashtable gCache = new Hashtable();
private int gCacheCount = 0;
private int gInteractions = 0;
private int gSize = 100;
private int gMinLifeTime = 1 * 60 * 1000;
private int gMaxLifeTime = 5 * 60 * 1000;
private int gMaxInteractions = 250;
//////////////////////////
//////////
//////////
//////////
//////////
//////////
////
// Constructor
//////////////////////////
//////////
//////////
//////////
//////////
//////////
////
private Caching(String pName)
{
gName = pName;
}
//////////////////////////
//////////
//////////
//////////
//////////
//////////
////
// Methods
//////////////////////////
//////////
//////////
//////////
//////////
//////////
////
public static Caching getCache(String pName)
{
Caching vCaching = (Caching)gCaches.get(pName
);
if (vCaching == null)
{
vCaching = new Caching(pName);
gCaches.put(pName, vCaching);
}
return vCaching;
}
public static Caching getCache(String pName, int pMinLifeTime, int pMaxLifeTime, int pSize)
{
Caching vCaching = getCache(pName);
vCaching.setMinLifeTime(pM
inLifeTime
);
vCaching.setMaxLifeTime(pM
axLifeTime
);
vCaching.gSize = pSize;
return vCaching;
}
public static Caching getCache(String pName, int pMinLifeTime, int pMaxLifeTime, int pSize, int pMaxInteractions)
{
Caching vCaching = getCache(pName);
vCaching.setMinLifeTime(pM
inLifeTime
);
vCaching.setMaxLifeTime(pM
axLifeTime
);
vCaching.gSize = pSize;
vCaching.setMaxInteraction
s(pMaxInte
ractions);
return vCaching;
}
public String getName()
{
return gName;
}
public synchronized Object get(Object pKey)
{
gInteractions++;
CacheObject vCacheObject = (CacheObject)gCache.get(pK
ey);
if (vCacheObject == null)
{
gLog.info(gCacheCount + "\tget(" + pKey + ") NOT IN CACHE ");
return null;
}
else
{
if (hasMaxAge(vCacheObject))
{
gCacheCount--;
gLog.debug(gCacheCount + "\tREMOVE " + vCacheObject);
gLog.info(gCacheCount + "\tget(" + pKey + ") NOT IN CACHE ");
gCache.remove(pKey);
return null;
}
else
{
gLog.info(gCacheCount + "\tget(" + pKey + ") " + vCacheObject);
}
}
vCacheObject.hit();
if (gInteractions > gMaxInteractions){
cleanCache();
}
return vCacheObject.getObject();
}
public synchronized Object remove(Object pKey)
{
Object vObject = gCache.remove(pKey);
if (vObject != null)
{
gCacheCount--;
}
return vObject;
}
public synchronized long getAge(Object pKey)
{
CacheObject vCacheObject = (CacheObject)gCache.get(pK
ey);
if (vCacheObject == null)
{
gLog.info(gCacheCount + "\tgetAge(" + pKey + ") NOT IN CACHE ");
throw new RuntimeException("Object " + pKey + " NOT IN CACHE");
}
else
{
return vCacheObject.getAge();
}
}
public synchronized void put(Object pKey, Object pObject)
{
gInteractions++;
CacheObject vCacheObject = (CacheObject)gCache.get(pK
ey);
if (vCacheObject != null)
{
return;
}
if (gInteractions < gMaxInteractions && gCacheCount < gSize)
{
gCacheCount++;
vCacheObject = new CacheObject(pKey, pObject);
gLog.debug(gCacheCount + " " + gInteractions + "/" + gMaxInteractions + "\tADD " + vCacheObject);
vCacheObject.hit();
gCache.put(pKey, vCacheObject);
}
else
{
cleanCache();
if (gCacheCount < gSize)
{
gCacheCount++;
vCacheObject = new CacheObject(pKey, pObject);
gLog.debug(gCacheCount + " " + gInteractions + "/" + gMaxInteractions + "\tADD " + vCacheObject);
vCacheObject.hit();
gCache.put(pKey, vCacheObject);
}
}
}
public synchronized void reset()
{
Enumeration vKeys = gCache.keys();
while(vKeys.hasMoreElement
s())
{
Object vKey = vKeys.nextElement();
gCache.remove(vKey);
}
gCache = new Hashtable();
}
private void cleanCache()
{
gInteractions = 0;
Object[] vObject = gCache.values().toArray();
Arrays.sort(vObject);
boolean vPlaceFree = false;
for (int i = 0; i < vObject.length; i++)
{
CacheObject vCacheObject = (CacheObject)vObject[i];
if (!vPlaceFree && hasMinAge(vCacheObject) && i < vObject.length * 0.66)
{
gCacheCount--;
gLog.debug(gCacheCount + "\tREMOVE " + vCacheObject);
gCache.remove(vCacheObject
.getKey())
;
vPlaceFree = true;
}
else if (hasMaxAge(vCacheObject))
{
gCacheCount--;
gLog.debug(gCacheCount + "\tREMOVE " + vCacheObject);
gCache.remove(vCacheObject
.getKey())
;
vPlaceFree = true;
}
}
}
private boolean hasMinAge(CacheObject vCacheObject)
{
return vCacheObject.getAge() > (long) gMinLifeTime;
}
private boolean hasMaxAge(CacheObject vCacheObject)
{
return vCacheObject.getAge() > (long) gMaxLifeTime;
}
public void setSize(int pSize)
{
gSize = pSize;
}
public void setMinLifeTime(int pMinLifeTime)
{
gMinLifeTime = pMinLifeTime * 60 * 1000;
}
public void setMaxInteractions(int pMaxInteractions)
{
gMaxInteractions = pMaxInteractions;
}
public void setMaxLifeTime(int pMaxLifeTime)
{
if (pMaxLifeTime == Integer.MAX_VALUE)
{
gMaxLifeTime = Integer.MAX_VALUE;
}
else
{
gMaxLifeTime = pMaxLifeTime * 60 * 1000;
}
}
public int getCurrentSize()
{
return gCacheCount;
}
//////////////////////////
//////////
//////////
//////////
//////////
//////////
////
// Inner Class
//////////////////////////
//////////
//////////
//////////
//////////
//////////
////
private class CacheObject implements Comparable
{
//////////////////////////
//////////
//////////
//////////
///////
// Internal Fields
//////////////////////////
//////////
//////////
//////////
///////
private Object gKey;
private Object gObject;
private long gCreationTime;
private int gHits;
//////////////////////////
//////////
//////////
//////////
///////
// Constructor
//////////////////////////
//////////
//////////
//////////
///////
CacheObject(Object pKey, Object pObject)
{
gKey = pKey;
gObject = pObject;
gCreationTime = System.currentTimeMillis()
;
gHits = 0;
}
public long getAge()
{
return System.currentTimeMillis()
- gCreationTime;
}
public float getHitRate()
{
float vHitRate = 0.0f;
long vAge = getAge();
if (vAge != 0L && vAge < (long) (gMaxLifeTime + gMinLifeTime))
{
vHitRate = ((float)(gHits * 60 * 1000)) / (float) getAge();
}
return vHitRate;
}
public void hit()
{
gHits++;
}
public Object getKey()
{
return gKey;
}
public Object getObject()
{
return gObject;
}
public String toString()
{
return "CACHE:" + gKey + " age:" + getAgeFormat() +
" hitrate:" + getHitRate() + "hit/min";
}
private String getAgeFormat()
{
long vAge = getAge();
long vSec = (vAge / 1000) % 60;
long vMin = vAge / 60000;
return vMin + ":" + vSec;
}
//////////////////////////
//////////
//////////
//////////
///////
// Implements Comparable
//////////////////////////
//////////
//////////
//////////
///////
public int compareTo(Object vObject)
{
CacheObject vCacheObject = (CacheObject)vObject;
return (int)((getHitRate() * 100) - (vCacheObject.getHitRate()
* 100));
}
}
}