问题

使用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>

Ehcache BigMemory: 摆脱GC困扰的更多相关文章

  1. Ehcache BigMemory: 摆脱GC困扰(转)

    问题 使用java开源项目经常需要调优jvm,以优化gc.对于gc,如果对象都是短时对象,那么jvm相对容易优化,假如碰上像solr使用自带java cache的项目,那么gc严重受限于cache,因 ...

  2. 成为Java GC专家(4)—Apache的MaxClients参数详解及其在Tomcat执行FullGC时的影响

    下面我们看一下Apache的 MaxClients 参数在Full GC 发生时是如何影响系统的. 大部分开发人员都知道在由于GC发生而导致的”停止世界现象(STW) “(详细请参见Understan ...

  3. 【Unity优化】构建一个拒绝GC的List

    版权声明:本文为博主原创文章,欢迎转载.请保留博主链接:http://blog.csdn.net/andrewfan 上篇文章<[Unity优化]Unity中究竟能不能使用foreach?> ...

  4. 在.net中读写config文件的各种方法

    阅读目录 开始 config文件 - 自定义配置节点 config文件 - Property config文件 - Element config文件 - CDATA config文件 - Collec ...

  5. SpringMVC 学习-返回字符串中文乱码问题解决

    一.使用 SpringMVC 框架时,如果 HTTP 请求资源返回的是中文字符串,则会出现乱码.原因如下: SpringMVC 框架可以使用 @RequestBody 和 @ResponseBody ...

  6. WPF程序中App.Config文件的读与写

    WPF程序中的App.Config文件是我们应用程序中经常使用的一种配置文件,System.Configuration.dll文件中提供了大量的读写的配置,所以它是一种高效的程序配置方式,那么今天我就 ...

  7. 通用订单搜索的API设计得失录

    先把 Joshua Bloch 大神的 API PDF 放在这里膜拜下:"How to Design a Good API and Why it Matters.pdf" 总述 在 ...

  8. Spring:面向切片编程

    在之前我们记录Spring的随笔当中,都是记录的Spring如何对对象进行注入,如何对对象的属性值进行注入,即我们讲解的很大部分都是Spring的其中一个核心概念——依赖注入(或者说是控制翻转,IOC ...

  9. 在.net中读写config文件的各种方法(自定义config节点)

    http://www.cnblogs.com/fish-li/archive/2011/12/18/2292037.html 阅读目录 开始 config文件 - 自定义配置节点 config文件 - ...

随机推荐

  1. [linux]windows无法访问samba的安全性问题(关闭selinux)

    背景 在某一天重启了虚拟机的 linux 之后,我的 windows 在连接上 samba 之后,点击某些文件夹的时候,会出现没有权限打开的情况.这问题折腾了我一度重新配置了好几次 samba 的配置 ...

  2. vios 虚拟光驱 安装vioc

    一.VIO server 创建虚拟光驱 1 检查是否创建Library $lsrep 2 创建 VMLibrary :vg 和size都可以自己定义 $mkrep -sp rootvg -size 1 ...

  3. CSS布局技巧 -- 纯CSS让子元素的宽度总和决定其父元素的宽度

    使用场景 在移动端屏幕宽度有限的前提下,使用横向滚动的方式展示更多的内容.在这样的需求下,希望父元素作为容器,其宽度可以又横向排列资源的总宽度动态撑开,超过祖父元素的宽度:在不超过祖父元素时,自动继承 ...

  4. SaaS模式给用户带来的优势

    这两年SaaS服务在中国越来越受欢迎,企业正在从使用本地化软件向SaaS服务转变.由于企业用户人力成本的上升.移动终端设备的兴起以及共享经济对企业的影响,企业采用经营设备.软件的方式也在逐渐发生着变化 ...

  5. Maven仓库管理-Nexus

    Maven仓库管理-Nexus @import url(http://www.blogjava.net/CuteSoft_Client/CuteEditor/Load.ashx?type=style& ...

  6. C#开发Android环境搭建

    目前破解比较稳定的版本(我亲自尝试过的)是4.2. wuleba上的4.6,4.8,4.10 破解均会出现各种问题. 1 当前电脑账户最好是使用英文账号,而不要使用汉字,否则路径会出现乱码问题. 2 ...

  7. HTML5所有标签汇总

    来自lampbrother兄弟连HTML5与CSS3教程.<xmp> 结构标签:(块状元素) 有意义的div<article>     标记定义一篇文章<header&g ...

  8. ajax实现手机获取验证码

    <script type="text/javascript"> var InterValObj; //timer变量,控制时间 var count = 60; //间隔 ...

  9. Document-对象属性和常用的对象方法

    Document-对象属性和常用的对象方法 对象属性 document.title                           //设置文档标题等价于HTML的title标签 document ...

  10. react 15来了

    有段时间没做react的项目了,前两天才发现react搞了一个不太小的动作,不是遵循原来的小版本号迭代,从0.14.x继续更新,而是直接跳到了15.0.X.虽然业界一直有这个观点,0.x的版本视为非稳 ...