当前位置: 首页 > 知识库问答 >
问题:

EhCache使用太多堆内存来存储值

华修永
2023-03-14

我用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;
}

下面是内存和CPU配置文件屏幕截图

共有3个答案

姚晋
2023-03-14

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

请通过http://blog.terracotta.org/2015/04/13/ehcache-storage-tier-model-with-offheap/

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

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

归鸿朗
2023-03-14

我还遇到过ehcache使用太多内存以及在非常简单的测试示例上出现“MappedByteBufferSource异步刷新线程”错误的问题。根据你需要多少功能,我个人会使用BigArrayList。它可以像普通的ArrayList一样使用,并将使用LRU策略为您处理从磁盘到内存的所有I/O。您可以将对象列表作为元素存储在BigArrayList中,并像处理普通ArrayList一样对其进行操作。根据元素的大小和可用内存,您可能需要尝试在内存中存储多少元素。它的优点是易于使用,而且确实有效。

陆伟
2023-03-14

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

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


java字符串对象为您要存储的每个字符串添加38个字节,每个字符串为您的整数键存储16个字节(8个用于看守4个用于整数到16个字节)。对于32位环境,这将向您的最大文件添加约550mb。在64位环境中,情况会变得更糟。

我猜,你添加了大约1GB的对象开销到你的594 mb文件中,我没有考虑ehache使用的Element对象。如果你研究那个对象,你会很清楚内存浪费在哪里。

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

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

我将文件的文本存储在一个String对象中,并创建一个单独的int[](而不是intger[])数组,用于保存每行的偏移量。

因此,获取行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数组。字符串对象保存文本,数组保存偏移量。

 类似资料:
  • 我在Python3.5上使用selenium,在ububtu vps上使用chrome webdriver,当我运行一个非常基本的脚本(导航到站点,输入登录字段,单击)时,内存占用增加了400MB,cpu占用增加到100%。我可以做些什么来降低这个数字,或者如果没有的话,有什么其他的办法吗? 我正在python中测试selenium,但我计划在java中使用它进行一个项目,其中内存使用对我来说是一

  • 我正在使用框架用iPhone摄像头捕捉视频,我的代码: 在之前,一切都很顺利,内存被限制在3M,但在之后,内存使用量每秒增加0.06M,几分钟后,应用程序会因为内存警告而崩溃。似乎占用了太多内存,并且可能存在内存泄漏问题。 那么如何减少内存使用量呢? iOS版本:7.1.1

  • 如EhCache留档所述: 实际上,这意味着持久性内存中缓存将启动,其所有元素都将在磁盘上。[...]因此,Ehcache设计不会在启动时将它们全部加载到内存中,而是根据需要懒惰地加载它们。 我希望内存缓存启动时将所有元素都存储在内存中,我该如何实现? 这是因为我们的网站对缓存执行了大量的访问,所以我们第一次访问网站时,它的响应时间非常长。

  • 我并不了解Java特别是Java调试,但在Jenkins中使用Monitoring进行堆转储,然后在Eclipse中使用MAT对其进行解码,显示总内存使用量为169.4MB,而在Jenkins中Monitoring似乎经常使用内存,GCs也经常运行。-XMX是4G。 为什么我只有169.4MB的mat?可能是因为在进行转储之前,Jenkins执行了GC吗?如果是,我是否可以避免它以看到完整的内存转

  • 我们在应用程序中使用ehcache。请看以下配置: 既然我们已经配置为eternal="true ",那么它会永远创建缓存吗?。磁盘空间有可能用完吗? 对磁盘存储的性能会有什么影响?。肯定比内存缓存慢,但是影响有多大。 如果磁盘中存储了更多缓存,是否会导致执行多个文件操作的IO问题? 请建议生产级应用的最佳实践。假设我们有一个3 GB的堆内存和25000个并发用户访问应用程序。但是,我们的应用程序

  • 我有一个tomcat用ignite进行会话聚类。我有一个示例登录调用,它为一个用户创建一个会话,在成功登录之后,我看到下面的日志打印出来,其中堆大小波动很大。 我的问题是 为什么整个堆大小是波动的?。 感谢任何指点。 问候你,阿拉温德