Lucene在索引数据比较少的时候内存问题不是很明显,但如果索引文件有几个G的时候,内存就会出现溢出问题.这个问题是由于Lucene的内部Bug引起的,如果在搜索时设置了排序,则它会缓存相关数据,但在下一次搜索时,它没有清除内部的一些缓存数据,所以会造成内存溢出.这个问题的解决办法就是改Lucene的源代码.
修改步骤如下:
1.修改Lucene源代码中Index目录中的IndexReader.cs文件,在其中加上如下代码:
public string m_cacheKey = null; (这一行代码主要用于Lucene内部用缓存的键值),以后清除缓存就用这个键值.
2.修改Lucene源代码中Search目录中的IndexSearcher.cs文件,修改其中的Close方法代码如下:
public override void Close()
{
//清除缓存数据
if (!string.IsNullOrEmpty(reader.m_cacheKey))
{
if (null != FieldSortedHitQueue.Comparators)
{
FieldSortedHitQueue.Comparators.ReleaseCache(reader.m_cacheKey);
}
Lucene.Net.Search.FieldCache_Fields.DEFAULT.ReleaseFieldCache(reader.m_cacheKey);
Lucene.Net.Search.ExtendedFieldCache_Fields.EXT_DEFAULT.ReleaseExtendedFieldCache(reader.m_cacheKey);
// 立即回收垃圾
GC.Collect();
}
//关闭读取器
if (closeReader)
reader.Close();
}
3.修改Lucene源代码中Search目录中的FieldCache.cs文件,修改其中的接口public interface FieldCache,并添加接口方法,方法代码如下:
//用于清除缓存
void ReleaseFieldCache(string strCacheKey);
4.修改Lucene源代码中Search目录中的FieldCacheImpl.cs文件,添加下列方法,
代码如下:
//用于清除缓存
public void ReleaseFieldCache(string strCacheKey)
{
bytesCache.ReleaseCache(strCacheKey);
shortsCache.ReleaseCache(strCacheKey);
intsCache.ReleaseCache(strCacheKey);
floatsCache.ReleaseCache(strCacheKey);
stringsCache.ReleaseCache(strCacheKey);
stringsIndexCache.ReleaseCache(strCacheKey);
autoCache.ReleaseCache(strCacheKey);
customCache.ReleaseCache(strCacheKey);
}
修改内部类:internal abstract class Cache,添加方法如下:
//用于清除缓存
public void ReleaseCache(string strCacheKey)
{
if (null != readerCache)
{
lock (readerCache.SyncRoot)
{
if (null != readerCache[strCacheKey])
{
((System.Collections.Hashtable)readerCache[strCacheKey]).Clear();
}
}
}
}
修改方法Get:
public virtual System.Object Get(IndexReader reader, System.Object key)
{
System.Collections.IDictionary innerCache;
System.Object value_Renamed;
lock (readerCache.SyncRoot)
{
//改键值为静态值
innerCache = (System.Collections.IDictionary)readerCache[reader.m_cacheKey];
//innerCache = (System.Collections.IDictionary) readerCache[reader];
if (innerCache == null)
{
innerCache = new System.Collections.Hashtable();
//改键值为静态值
readerCache[reader.m_cacheKey] = innerCache;
//readerCache[reader] = innerCache;
value_Renamed = null;
}
else
{
value_Renamed = innerCache[key];
}
if (value_Renamed == null)
{
value_Renamed = new CreationPlaceholder();
innerCache[key] = value_Renamed;
}
}
if (value_Renamed is CreationPlaceholder)
{
lock (value_Renamed)
{
CreationPlaceholder progress = (CreationPlaceholder) value_Renamed;
if (progress.value_Renamed == null)
{
progress.value_Renamed = CreateValue(reader, key);
lock (readerCache.SyncRoot)
{
innerCache[key] = progress.value_Renamed;
}
}
return progress.value_Renamed;
}
}
return value_Renamed;
}
5.修改Lucene源代码中Search目录中的ExtendedFieldCache.cs文件,修改其中的接口public interface ExtendedFieldCache : FieldCache,并添加接口方法,方法代码如下:
//用于清除缓存
void ReleaseExtendedFieldCache(string strCacheKey);
6.修改Lucene源代码中Search目录中的ExtendedFieldCacheImpl.cs文件,添加下列方法,代码如下:
//用于清除缓存
public void ReleaseExtendedFieldCache(string strCacheKey)
{
longsCache.ReleaseCache(strCacheKey);
doublesCache.ReleaseCache(strCacheKey);
autoCache.ReleaseCache(strCacheKey);
}
通过上述6个步骤,内存溢出问题就可以解决了,但还有一个需要注意的就是在更新索引时,一定要调用如下代码,才能清掉缓存:
//清缓排序缓存数据
IndexSearcher.Close();
IndexReader.Close();