Ehcache BigMemory: 摆脱GC困扰(转)
问题
使用java开源项目经常需要调优jvm,以优化gc。对于gc,如果对象都是短时对象,那么jvm相对容易优化,假如碰上像solr使用自带java cache的项目,那么gc严重受限于cache,因为cache对象并非短时对象,以至于young gc常常伴有大量的内存对象拷贝,严重影响gc性能。
Ehcache BigMemory
Java的内存管理机制极其不适用于cache,最好的办法是使用jni实现的cache系统。另一种通用办法:Ehcache BigMemory(http://ehcache.org/)。BigMemory extends Ehcache's' capabilities with an off-heap store that frees you from GC’s constraints.
对于BigMemory,直接下载免费的32G限制的版本(注: 每个jvm进程最多使用32G的off-heap空间,对大多数应用已足够)。
关于如何使用,参见官方文档: http://terracotta.org/documentation/4.0/bigmemorygo/get-started
使用示例可参考代码中自带的样例:bigmemory-go-4.0.0/code-samples/src/main/java/com/bigmemory/samples
样例代码缺少编译配置build.xml, 将下面的 build.xml 放在 bigmemory-go-4.0.0/code-samples 即可使用ant 编译示例代码:

- <project name="bigmemory" basedir=".">
- <property name="build.dir" value="${basedir}/build" />
- <property name="src.class.dir" value="${build.dir}" />
- <property name="src.dir" value="${basedir}/src" />
- <property name="lib.dir" value="${basedir}/../lib" />
- <property name="config.dir" value="${basedir}/config" />
- <path id="base.classpath">
- <pathelement location="${src.class.dir}" />
- <pathelement location="${config.dir}" />
- <fileset dir="${lib.dir}">
- <include name="**/*.jar" />
- </fileset>
- </path>
- <path id="classpath">
- <path refid="base.classpath" />
- <fileset dir="${lib.dir}">
- <include name="**/*.jar" />
- </fileset>
- </path>
- <path id="build.src.path">
- <pathelement location="${src.class.dir}" />
- </path>
- <target name="clean" description="clean">
- <delete dir="${build.dir}" />
- </target>
- <target name="compile" depends="clean" description="compile">
- <mkdir dir="${src.class.dir}" />
- <javac srcdir="${src.dir}" destdir="${src.class.dir}" source="1.6" debug="on" encoding="utf-8" includeantruntime="false">
- <classpath refid="base.classpath" />
- </javac>
- </target>
- <target name="jar" depends="compile" description="jar">
- <jar destfile="${build.dir}/bigmemory.jar">
- <fileset dir="${src.class.dir}">
- <exclude name="**/timer/**" />
- </fileset>
- </jar>
- </target>
- </project>

配置说明:bigmemory-go-4.0.0/config-samples/ehcache.xml 详细说明了配置参数。
限制:
1、存储对象全部使用 java.io.Serializable 做序列化和反序列化,性能有损失。
2、off-heap空间一经分配不可调整。
solr缓存
引入Ehcache bigmemory是为了优化solr的缓存。下面代码是基于solr cache基类实现的ehcache缓存类,使用上同于solr.FastLRUCache,需要ehcache的外部配置文件。

- package org.apache.solr.search;
- import org.apache.solr.common.SolrException;
- import org.apache.solr.common.util.NamedList;
- import org.apache.solr.common.util.SimpleOrderedMap;
- import org.apache.solr.core.SolrCore;
- import java.util.*;
- import java.util.concurrent.atomic.AtomicLong;
- import java.io.IOException;
- import java.net.URL;
- import net.sf.ehcache.Cache;
- import net.sf.ehcache.CacheManager;
- import net.sf.ehcache.Element;
- import net.sf.ehcache.config.CacheConfiguration;
- import net.sf.ehcache.config.Configuration;
- import net.sf.ehcache.config.MemoryUnit;
- /**
- * @version $Id: EhCacheWrapper.java 2013-03-27 zhenjing chen $
- */
- public class EhCacheWrapper implements SolrCache {
- /* An instance of this class will be shared across multiple instances
- * of an LRUCache at the same time. Make sure everything is thread safe.
- */
- private static class CumulativeStats {
- AtomicLong lookups = new AtomicLong();
- AtomicLong hits = new AtomicLong();
- AtomicLong inserts = new AtomicLong();
- AtomicLong evictions = new AtomicLong();
- }
- private CumulativeStats stats;
- // per instance stats. The synchronization used for the map will also be
- // used for updating these statistics (and hence they are not AtomicLongs
- private long lookups;
- private long hits;
- private long inserts;
- private long evictions;
- private long warmupTime = 0;
- private CacheManager manager = null;
- private Cache map;
- private String name;
- private String cache_name;
- private int autowarmCount;
- private State state;
- private CacheRegenerator regenerator;
- private String description="Eh LRU Cache";
- private static int cache_index = 0;
- private static Map<String, CacheManager> managerPool = null;
- private static Map<String, Integer> managerFlag = null;
- private static CacheManager managerTemplate = null;
- static{
- managerPool = new HashMap<String, CacheManager>();
- managerFlag = new HashMap<String, Integer>();
- managerTemplate = new CacheManager("/data/conf/ehcache.xml");
- }
- private Cache GetCache() {
- // use cache pool
- Set<String> set = managerFlag.keySet();
- Iterator<String> it = set.iterator();
- while(it.hasNext()) {
- String cacheName = it.next();
- if( managerFlag.get(cacheName) == 0 ) { // not used
- manager = managerPool.get(cacheName);
- System.out.println("EhCacheWrapper Cache Name(Pool): " + cacheName);
- managerFlag.put(cacheName, 1);
- cache_name = cacheName;
- return manager.getCache(cacheName);
- }
- }
- // add zhenjing
- String cacheName = name + cache_index;
- System.out.println("EhCacheWrapper Cache Name: " + cacheName);
- // create Cache from template
- Cache orig = managerTemplate.getCache(name);
- CacheConfiguration configTmp = orig.getCacheConfiguration();
- configTmp.setName(cacheName);
- Configuration managerConfiguration = new Configuration();
- managerConfiguration.setName(cacheName);
- manager = new CacheManager(managerConfiguration.cache(configTmp));
- // put to cache pool
- managerFlag.put(cacheName, 1);
- managerPool.put(cacheName, manager);
- // get cache
- cache_index++;
- cache_name = cacheName;
- return manager.getCache(cacheName);
- }
- public Object init(Map args, Object persistence, CacheRegenerator regenerator) {
- state=State.CREATED;
- this.regenerator = regenerator;
- name = (String)args.get("name");
- String str = (String)args.get("size");
- final int limit = str==null ? 1024 : Integer.parseInt(str);
- str = (String)args.get("initialSize");
- final int initialSize = Math.min(str==null ? 1024 : Integer.parseInt(str), limit);
- str = (String)args.get("autowarmCount");
- autowarmCount = str==null ? 0 : Integer.parseInt(str);
- // get cache
- map = GetCache();
- CacheConfiguration config = map.getCacheConfiguration();
- description = "Eh LRU Cache(MaxBytesLocalOffHeap=" + config.getMaxBytesLocalOffHeap() + ", MaxBytesLocalHeap=" + config.getMaxBytesLocalHeap() + ", MaxEntriesLocalHeap=" + config.getMaxEntriesLocalHeap() + ")";
- if (persistence==null) {
- // must be the first time a cache of this type is being created
- persistence = new CumulativeStats();
- }
- stats = (CumulativeStats)persistence;
- return persistence;
- }
- public String name() {
- return name;
- }
- public int size() {
- synchronized(map) {
- return map.getSize();
- }
- }
- public Object put(Object key, Object value) {
- synchronized (map) {
- if (state == State.LIVE) {
- stats.inserts.incrementAndGet();
- }
- // increment local inserts regardless of state???
- // it does make it more consistent with the current size...
- inserts++;
- map.put(new Element(key,value));
- return null; // fake the previous value associated with key.
- }
- }
- public Object get(Object key) {
- synchronized (map) {
- Element val = map.get(key);
- if (state == State.LIVE) {
- // only increment lookups and hits if we are live.
- lookups++;
- stats.lookups.incrementAndGet();
- if (val!=null) {
- hits++;
- stats.hits.incrementAndGet();
- //System.out.println(name + " EH Cache HIT. key=" + key.toString());
- }
- }
- if( val == null) return null;
- return val.getObjectValue();
- }
- }
- public void clear() {
- synchronized(map) {
- map.removeAll();
- }
- }
- public void setState(State state) {
- this.state = state;
- }
- public State getState() {
- return state;
- }
- public void warm(SolrIndexSearcher searcher, SolrCache old) throws IOException {
- return;
- }
- public void close() {
- clear();
- // flag un-used
- managerFlag.put(cache_name, 0);
- System.out.println("EhCacheWrapper Cache Name(Reuse): " + cache_name);
- }
- //////////////////////// SolrInfoMBeans methods //////////////////////
- public String getName() {
- return EhCacheWrapper.class.getName();
- }
- public String getVersion() {
- return SolrCore.version;
- }
- public String getDescription() {
- return description;
- }
- public Category getCategory() {
- return Category.CACHE;
- }
- public String getSourceId() {
- return " NULL ";
- }
- public String getSource() {
- return " NULL ";
- }
- public URL[] getDocs() {
- return null;
- }
- // returns a ratio, not a percent.
- private static String calcHitRatio(long lookups, long hits) {
- if (lookups==0) return "0.00";
- if (lookups==hits) return "1.00";
- int hundredths = (int)(hits*100/lookups); // rounded down
- if (hundredths < 10) return "0.0" + hundredths;
- return "0." + hundredths;
- /*** code to produce a percent, if we want it...
- int ones = (int)(hits*100 / lookups);
- int tenths = (int)(hits*1000 / lookups) - ones*10;
- return Integer.toString(ones) + '.' + tenths;
- ***/
- }
- public NamedList getStatistics() {
- NamedList lst = new SimpleOrderedMap();
- synchronized (map) {
- lst.add("lookups", lookups);
- lst.add("hits", hits);
- lst.add("hitratio", calcHitRatio(lookups,hits));
- lst.add("inserts", inserts);
- lst.add("evictions", evictions);
- lst.add("size", map.getSize());
- }
- lst.add("warmupTime", warmupTime);
- long clookups = stats.lookups.get();
- long chits = stats.hits.get();
- lst.add("cumulative_lookups", clookups);
- lst.add("cumulative_hits", chits);
- lst.add("cumulative_hitratio", calcHitRatio(clookups,chits));
- lst.add("cumulative_inserts", stats.inserts.get());
- lst.add("cumulative_evictions", stats.evictions.get());
- return lst;
- }
- public String toString() {
- return name + getStatistics().toString();
- }
- }

外部ehcache.xml配置:

- <ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"
- updateCheck="false" monitoring="autodetect"
- dynamicConfig="true" name="config">
- <!--
- <cache name="filterCache"
- maxEntriesLocalHeap="1024"
- eternal="true"
- overflowToOffHeap="true"
- maxBytesLocalOffHeap="1g">
- </cache>
- <cache name="fieldValueCache"
- maxEntriesLocalHeap="1024"
- eternal="true"
- overflowToOffHeap="true"
- maxBytesLocalOffHeap="1g">
- </cache>
- -->
- <cache name="queryResultCache"
- maxEntriesLocalHeap="1"
- eternal="true"
- overflowToOffHeap="true"
- maxBytesLocalOffHeap="800m">
- </cache>
- <!-- ehcache not support documentCache, encoding format error.
- <cache name="documentCache"
- maxEntriesLocalHeap="1024"
- eternal="true"
- overflowToOffHeap="true"
- maxBytesLocalOffHeap="1g">
- </cache>
- -->
- </ehcache>
http://www.cnblogs.com/zhenjing/p/Ehcache_BigMemory.html
Ehcache BigMemory: 摆脱GC困扰(转)的更多相关文章
- Ehcache BigMemory: 摆脱GC困扰
问题 使用java开源项目经常需要调优jvm,以优化gc.对于gc,如果对象都是短时对象,那么jvm相对容易优化,假如碰上像solr使用自带java cache的项目,那么gc严重受限于cache,因 ...
- 成为Java GC专家(4)—Apache的MaxClients参数详解及其在Tomcat执行FullGC时的影响
下面我们看一下Apache的 MaxClients 参数在Full GC 发生时是如何影响系统的. 大部分开发人员都知道在由于GC发生而导致的”停止世界现象(STW) “(详细请参见Understan ...
- 【Unity优化】构建一个拒绝GC的List
版权声明:本文为博主原创文章,欢迎转载.请保留博主链接:http://blog.csdn.net/andrewfan 上篇文章<[Unity优化]Unity中究竟能不能使用foreach?> ...
- 在.net中读写config文件的各种方法
阅读目录 开始 config文件 - 自定义配置节点 config文件 - Property config文件 - Element config文件 - CDATA config文件 - Collec ...
- SpringMVC 学习-返回字符串中文乱码问题解决
一.使用 SpringMVC 框架时,如果 HTTP 请求资源返回的是中文字符串,则会出现乱码.原因如下: SpringMVC 框架可以使用 @RequestBody 和 @ResponseBody ...
- WPF程序中App.Config文件的读与写
WPF程序中的App.Config文件是我们应用程序中经常使用的一种配置文件,System.Configuration.dll文件中提供了大量的读写的配置,所以它是一种高效的程序配置方式,那么今天我就 ...
- 通用订单搜索的API设计得失录
先把 Joshua Bloch 大神的 API PDF 放在这里膜拜下:"How to Design a Good API and Why it Matters.pdf" 总述 在 ...
- Spring:面向切片编程
在之前我们记录Spring的随笔当中,都是记录的Spring如何对对象进行注入,如何对对象的属性值进行注入,即我们讲解的很大部分都是Spring的其中一个核心概念——依赖注入(或者说是控制翻转,IOC ...
- 在.net中读写config文件的各种方法(自定义config节点)
http://www.cnblogs.com/fish-li/archive/2011/12/18/2292037.html 阅读目录 开始 config文件 - 自定义配置节点 config文件 - ...
随机推荐
- ubuntu oracle jdk
sudo add-apt-repository ppa:webupd8team/java sudo apt-get update sudo apt-get install oracle-javaX-i ...
- Linux内核的同步机制---自旋锁
自旋锁的思考:http://bbs.chinaunix.net/thread-2333160-1-1.html 近期在看宋宝华的<设备驱动开发具体解释>第二版.看到自旋锁的部分,有些疑惑. ...
- 每日回顾Shell —cat,tail,head
Shell中常常会用到cat命令.可是总是不是特别清楚: cat命令的用途是连接文件或标准输入并打印. 这个命令经常使用来显示文件内容.或者将几个文件连接起来显示.或者从标准输入读取内容并显示,它常与 ...
- Tomcat中更改网站根目录和默认页的配置方法
1.tomcat原来的默认根目录是http://localhost:8080,如果想修改访问的根目录,可以这样: 找到tomcat的server.xml(在conf目录下),找到: <Host ...
- Google 开源项目的风格指南
谷歌C++代码风格指南.农业所需的代码.更难得的是不FQ,决定性的最爱!! . http://zh-google-styleguide.readthedocs.org/en/latest/google ...
- jenkins集群加入Windows 2012 server作为slave
必须安装.net framework 3.5, 參考: http://technet.microsoft.com/en-us/library/dn482071.aspx 不要在windows 2012 ...
- Python 的PyCurl模块使用
PycURl是一个C语言写的libcurl的python绑定库.libcurl 是一个自由的,并且容易使用的用在客户端的 URL 传输库.它的功能很强大,PycURL 是一个非常快速(参考多并发操作) ...
- sql dateDiff函数
当月的数据select * from MOPICK where dateDiff(m,getdate(),START_DATE)=0
- i++和i--运算符优先级
1.问题背景 /** * 測试i++和i-- */ package com.you.model; /** * @author YouHaiDong * @date 2014-08-16 */ @Sup ...
- 【程序员联盟】官网上线啦!coderunity.com
内容简介 欢天喜地,[程序员联盟]官网上线咯(此处应该有鸡蛋丢过来...) [程序员联盟]官网 大家也许会问:“这几天小编都没出文章,跑哪里happy去啦?是不是偷懒去了?” 小编:“臣妾冤枉啊.” ...