Java EhCache使用了太多的堆内存来存储值

Java EhCache使用了太多的堆内存来存储值,java,ehcache,Java,Ehcache,我使用EhCache来缓存2.5 Gb的数据。我有32个大小不同的文件,但总数据量为2.5 Gb。我使用12G堆内存运行代码,但整个数据集无法容纳12G数据,它会溢出到磁盘。您能告诉我配置有什么问题吗?或者EhCache总是占用那么多内存。我将整数作为键,列表作为值的所有缓存(分隔文件的记录) 使用的JVM参数%JAVA\u HOME%\bin\JAVA.exe-server-d64-Xms12G-Xmx12G-XX:+UseG1GC-XX:-省略StackTraceInFastThrow 下面

我使用EhCache来缓存2.5 Gb的数据。我有32个大小不同的文件,但总数据量为2.5 Gb。我使用12G堆内存运行代码,但整个数据集无法容纳12G数据,它会溢出到磁盘。您能告诉我配置有什么问题吗?或者EhCache总是占用那么多内存。我将整数作为键,列表作为值的所有缓存(分隔文件的记录)

使用的JVM参数
%JAVA\u HOME%\bin\JAVA.exe-server-d64-Xms12G-Xmx12G-XX:+UseG1GC-XX:-省略StackTraceInFastThrow

下面是我用于缓存的代码片段

//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;
}
//弹簧配置
@Bean(destromethod=“shutdown”,name=“batchCache”)
public net.sf.ehcache.CacheManager ehCacheManager(){
DiskStoreConfiguration DiskStoreConfiguration=新的DiskStoreConfiguration();
设置路径(“C:\\DiskCache”);
net.sf.ehcache.config.Configuration config=new net.sf.ehcache.config.Configuration();
config.setName(“NAV_批次”);
config.addDiskStore(diskStoreConfiguration);
//setMaxBytesLocalHeap(MemoryUnit.GIGABYTES.toBytes(10));
net.sf.ehcache.CacheManager mgr=net.sf.ehcache.CacheManager.newInstance(配置);
经理clearAll();
返回经理;
}
//获取缓存管理器的代码
private CacheManager CacheManager=(CacheManager)ApplicationContextProvider.getApplicationContext().getBean(“batchCache”);
//缓存的类级副本
专用缓存;
受保护的缓存getCache(){
if(null==缓存){
Cache-managerCache=cacheManager.getCache(cacheName);
if(null==managerCache){
cache=createCache();
}否则{
cache=managerCache;
}
}
返回缓存;
}
//键是整数,值总是字符串列表
受保护的void putListRecordsInCache(对象键、列表值){
元素=新元素(键、值);
getCache().put(元素);
}
公共列表getValues(对象键){
元素e=getCache().get(键);
List dataList=新建LinkedList();
如果(null==e){
返回数据列表;
}
列表行=(列表)e.getObjectValue();
用于(字符串行:行){
T T=getMapper().convertValuesToObject(行,null);
添加(t);
}
返回数据列表;
}
私有缓存createCache(){
Cache-managerCache=cacheManager.getCache(cacheName);
if(null==managerCache){
managerCache=新缓存(cacheConfig(cacheName));
//managerCache=(缓存)cacheManager.addCacheIfAbsent(managerCache);
cacheManager.addCache(managerCache);
}
返回管理器缓存;
}
专用缓存配置缓存配置(字符串名称){
CacheConfiguration config=新的CacheConfiguration();
config.name(name)
.MemoryStoreReceivingPolicy(“LRU”)
.永恒(真实)
.pinning(新的pinning配置().store(store.LOCALMEMORY))
.日志记录(错误)
.SizeOffPolicy(新的SizeOffPolicyConfiguration().maxDepth(100000).MaxDeptheExceededBehavior(“继续”))
.persistence(新PersistenceConfiguration().strategy(strategy.LOCALTEMPSWAP))
.统计数字(真实);
;
长尺寸=-1;
试一试{
size=Files.size(FileSystems.getDefault().getPath(getDataFileLocation(),getFileName());
//System.out.println(新日期()+”,文件“+getDataFileLocation()+”/“+getFileName()+”的大小为“+Size+”字节”);
}捕获(IOE异常){
e、 printStackTrace();
}
如果(大小>0){
长缓存大小=大小*4;
maxBytesLocalHeap(cachesize,MemoryUnit.BYTES);
}否则{
如果(isValueGloballyCached){
config.maxBytesLocalHeap(100,MemoryUnit.MB);
}否则{
config.maxBytesLocalHeap(500,MemoryUnit.MB);
}
}
返回配置;
}
下面是内存和CPU配置文件屏幕截图


我认为ehcache.xml中有一个属性是maxBytesLocalOffheap,这在您的情况下可能很有用

请通过

如果您的ehcache版本低于2.3,则需要运行手动线程来查找过期内容,以便堆中有足够的空间

i、 后台线程定期执行getKeysWithExpiryCheck()。

问题不是“Ehcache占用了太多内存”。这个问题更像是“以一种高效的方式在内存中缓存巨大的文件”

此外,您希望随机访问文件的每一行

那么Ehcache这么贪心吗?
java string对象将38个字节添加到您要为
整数
键存储+16个字节的每个字符串中(8表示houskeeping+4表示int=rounds到16个字节)。这将为32位环境中的最大文件增加约550mb。在64位环境中,情况更糟

我猜,你在你的594 MB文件中添加了1GB的对象开销,我没有考虑<代码>元素< /C>对象EHCHACE使用。如果你仔细观察这个物体,你会非常清楚内存浪费在哪里

所以,我想我已经弄清楚了为什么你的2.5GB文件会占用这么多内存

一个可能的解决方案:假设您可以使用
单例
来缓存数据

我将文件的文本存储在一个
字符串
对象中,并创建一个单独的
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数组。
字符串
对象保存文本,数组保存偏移量。

我也遇到过ehcache使用(方式)过多内存以及在非常简单的测试示例上出现“MappedByteBufferSource异步刷新线程”错误的问题。根据您需要多少功能,我个人会使用。它可以像普通的ArrayList一样使用,并将使用LRU策略为您处理从磁盘到内存的所有I/O。你可以储存你的信用卡