我使用EhCache来缓存2.5 Gb的数据。我有32个不同大小的文件,但总数据量为2.5 Gb。我使用12G堆内存运行我的代码,但是整个数据集无法容纳12G数据,它会溢出到磁盘。你能否告诉我配置有什么问题,或者EhCache总是占用那么多内存。所有的缓存我把Integer作为键,List作为值(分隔文件的记录)
JVM参数使用%JAVA_HOME%\bin\java.exe -server -d64 -Xms12G -Xmx12G -XX:+UseG1GC -XX:-OmitStackTraceInFastThrow
以下是我用于缓存
的代码段//Spring Configuration
@Bean(destroyMethod = "shutdown",name="batchCache")
public net.sf.ehcache.CacheManager ehCacheManager() {
DiskStoreConfiguration diskStoreConfiguration = new DiskStoreConfiguration();
diskStoreConfiguration.setPath("C:\\DiskCache");
net.sf.ehcache.config.Configuration config = new net.sf.ehcache.config.Configuration();
config.setName("NAV_BATCH");
config.addDiskStore(diskStoreConfiguration);
//config.setMaxBytesLocalHeap(MemoryUnit.GIGABYTES.toBytes(10));
net.sf.ehcache.CacheManager mgr = net.sf.ehcache.CacheManager.newInstance(config);
mgr.clearAll();
return mgr;
}
//Code to Obtain Cache manager
private CacheManager cacheManager = (CacheManager) ApplicationContextProvider.getApplicationContext().getBean("batchCache");
//Class level copy of Cache
private Cache cache;
protected Cache getCache(){
if(null == cache){
Cache managerCache = cacheManager.getCache(cacheName);
if(null == managerCache){
cache = createCache();
}else{
cache = managerCache;
}
}
return cache;
}
//Key is Integer and Values is List of String always
protected void putListRecordsInCache(Object key,List<Object> values){
Element element = new Element(key, values);
getCache().put(element);
}
public List<T> getValues(Object key){
Element e = getCache().get(key);
List<T> dataList = new LinkedList<>();
if(null == e){
return dataList;
}
List<String> lines = (List<String>) e.getObjectValue();
for(String line:lines){
T t = getMapper().convertValuesToObject(line, null);
dataList.add(t);
}
return dataList;
}
private Cache createCache(){
Cache managerCache = cacheManager.getCache(cacheName);
if(null == managerCache){
managerCache = new Cache(cacheConfig(cacheName) );
//managerCache = (Cache) cacheManager.addCacheIfAbsent(managerCache);
cacheManager.addCache(managerCache);
}
return managerCache;
}
private CacheConfiguration cacheConfig(String name) {
CacheConfiguration config = new CacheConfiguration();
config.name(name)
.memoryStoreEvictionPolicy("LRU")
.eternal(true)
.pinning(new PinningConfiguration().store(Store.LOCALMEMORY))
.logging(false)
.sizeOfPolicy(new SizeOfPolicyConfiguration().maxDepth(100000).maxDepthExceededBehavior("CONTINUE"))
.persistence(new PersistenceConfiguration().strategy(Strategy.LOCALTEMPSWAP))
.statistics(true);
;
long size = -1;
try {
size = Files.size(FileSystems.getDefault().getPath(getDataFileLocation(), getFileName()));
//System.out.println(new Date()+",Size of file "+getDataFileLocation()+"/"+getFileName()+" is "+size+" bytes");
} catch (IOException e) {
e.printStackTrace();
}
if(size > 0){
long cachesize = size*4;
config.maxBytesLocalHeap(cachesize, MemoryUnit.BYTES);
}else{
if(isValueGloballyCached){
config.maxBytesLocalHeap(100, MemoryUnit.MEGABYTES);
}else{
config.maxBytesLocalHeap(500, MemoryUnit.MEGABYTES);
}
}
return config;
}
以下是内存和CPU配置文件截图
答案 0 :(得分:2)
问题不是&#34; Ehcache正在使用很多记忆&#34;。问题更像是&#34;以有效的方式在存储器中缓存大文件&#34;。
此外,您希望随机访问文件的每一行。
那么Ehcache就这么贪婪了吗?
java字符串对象为您要存储的每个字符串添加38个字节+为Integer
键添加16个字节(8个用于houskeeping + 4个用于int = rounds到16个字节)。这增加了ca.对于32位环境,550mb到您最大的文件。这在64位环境中变得更糟。
我猜,你的594 mb文件增加了大约1GB的对象开销,我没有考虑ehcache使用的Element
对象。如果你研究那个对象,你会很清楚内存被浪费的地方。
所以,我想我已经明确了为什么你的2.5 GB文件使用了这么多内存。
可能的解决方案:假设您可以使用Singleton
来缓存数据。
我会将文件的文本存储在一个String
对象中,并创建一个单独的int[]
(非Integer[]
)数组,该数组保存每行的偏移量。
因此,获取第1000
行的文字将是:
// text of the the file
String text;
// int array of offset.
int[] offset;
// todo: check if there is line 1000
int start = offset[999];
int end = offset.length > 1000 ? offset[1000] : text.length();
String line1000 = text.substring(start, end);
如果您遵循该方法,则会为每个文件获取字符串和int数组。 String
对象保存文本,数组保存偏移量。
答案 1 :(得分:1)
我在使用(方式)太多内存以及非常简单的测试示例中的“MappedByteBufferSource Async Flush Thread”错误时也遇到了麻烦。根据您需要的功能,我个人会使用issue tracker。它可以像常规ArrayList一样使用,并使用LRU策略为您处理从磁盘到内存的所有I / O.您可以将对象列表存储为BigArrayList中的元素,并像处理普通ArrayList一样对其进行操作。您可能需要尝试在内存中存储多少元素,具体取决于元素的大小和可用内存。优点是它易于使用且实际上有效。
答案 2 :(得分:0)
我认为ehcache.xml中有一个属性是maxBytesLocalOffheap,这可能对你的情况有用。
请完成 http://blog.terracotta.org/2015/04/13/ehcache-storage-tier-model-with-offheap/
如果您的ehcache版本低于2.3,则需要运行手动线程来查看过期内容,以便在堆中有足够的空间。
iebackground线程定期执行getKeysWithExpiryCheck()。