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文件 - ...
随机推荐
- SWT的CheckBoxTreeView的上级菜单与下级菜单的选中的实现
是不是很神奇? treeViewer.addCheckStateListener(new ICheckStateListener() { @Override public void checkStat ...
- hadoop日志分析
一.项目要求 本文讨论的日志处理方法中的日志,仅指Web日志.事实上并没有精确的定义,可能包含但不限于各种前端Webserver--apache.lighttpd.nginx.tomcat等产生的用户 ...
- pcie inbound、outbound及EP、RC间的互相訪问
Inbound:PCI域訪问存储器域 Outbound:存储器域訪问PCI域 RC訪问EP: RC存储器域->outbound->RC PCI域->EP PCI域->inbou ...
- 在android创建bitmap避免低记忆法
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="ht ...
- Qt4.8在Windows下的三种编程环境搭建
Qt4.8在Windows下的三种编程环境搭建 Qt的版本是按照不同的图形系统来划分的,目前分为四个版本:Win32版,适用于Windows平台:X11版,适合于使用了X系统的各种Linux和Unix ...
- 文件下载-SpringMVC中測试
直接改动文件路径就能够.其它都不须要改动,帮助类已经为大家写好,可直接使用 1.Scroller: /** * 下载文件 * @author liupeng * @param request * @p ...
- hdu5338 (二进制,双指针)
这种双循环的优化问题碰到过很多了.层出不穷. 但无非就是要利用前面循环时,所产生的信息,从而减少计算. 可以注意到log其实是不超过40的, 那么以这方面入手,时间复杂度就可以降为nlogn log= ...
- poj1185炮兵阵地
#include <iostream> #include <cstdio> #include <cmath> #include <algorithm> ...
- Google Map API V2密钥申请
之前用的都是v1,用的是MapView,好吧,仅仅能认命了.废话不再多说,開始android 的Google Maps Android API v2吧 之前參考了http://www.cnblogs. ...
- Unity入门
Unity入门 用unity做一个最简单的交互.(相当于Hello World)仅仅要最后能执行就算入门了. 第一步,要先用三维制作软件制作出我们须要的场景. 这儿使用的是Max2012(软件大小3. ...