问题

使用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 AtomicLongsprivate 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 poolSet<String> set = managerFlag.keySet();Iterator<String> it = set.iterator();while(it.hasNext()) {String cacheName = it.next();if( managerFlag.get(cacheName) == 0 ) {  // not usedmanager = managerPool.get(cacheName);System.out.println("EhCacheWrapper Cache Name(Pool): " + cacheName);managerFlag.put(cacheName, 1);cache_name = cacheName;return manager.getCache(cacheName);}}// add zhenjingString cacheName = name + cache_index;System.out.println("EhCacheWrapper Cache Name: " + cacheName);// create Cache from templateCache 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 poolmanagerFlag.put(cacheName, 1);managerPool.put(cacheName, manager);// get cachecache_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 cachemap = 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 createdpersistence = 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 downif (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困扰(转)相关推荐

  1. 如何快速摆脱焦虑困扰,重建内心平静?分享一份无需药物的指南,让你重拾自信并远离焦虑!

    ​​怎么有作用地缓解焦虑问题:全网最全面实用易懂的焦虑缓解指南,内含具体贴心细节不容错过 1. 有节奏的呼吸法: 这是许多缓解焦虑和减压技术里面最基本的一种方法.坐直或平躺,然后深深的吸气,从下腹部慢 ...

  2. 如何让路由器摆脱安全困扰

         很多网络管理员还没有认识到他们的路由器能够成为***的热点,路由器操作系统同网络操作系统一样容易受到***的***.大多数中小企业没有雇佣路由器工程师,也没有把这项功能当成一件必须要做的事情 ...

  3. win7开启uasp协议_摆脱低速困扰,ORICO NVME M.2 SSD硬盘盒轻松搞定

    对于SSD能够提升电脑运行速度,相信大家已经耳熟能详,无论是办公用的电脑还是游戏PC,提升运行速度最有效而又最经济的方式显然是将原电脑中的机械硬盘升级为SSD固态硬盘,而对于数据的搬运,U盘显然已经成 ...

  4. 什么东西可以改善睡眠,五款助眠好物帮你摆脱失眠困扰

    怎么样才能改善失眠症状和提高睡眠质量?这个其实跟自身有很大的因素,最主要还是要靠自身在心态上调节.但是有些时候真的难以克服自己的情绪,我们就只好借助一些外部的力量,来帮助我们入睡.下面这些是可以提高睡 ...

  5. 【NAS备份】摆脱丢数据的噩梦,群晖备份硬核实战教程分享

    前言 大家好,我是村雨Mura,本期来聊一聊我是如何用 NAS 轻松.完整地备份自己数据的. 首先,硬件再好不如备份 即便从小的线材到硬盘的质量都用最好的,也很难保证不丢数据,宇宙射线.硬盘不可逆衰减 ...

  6. 成为Java GC专家

    成为JavaGC专家Part I - 深入浅出Java垃圾回收机制 对于Java开发人员来说,了解垃圾回收机制(GC)有哪些好处呢?首先可以满足作为一名软件工程师的求知欲,其次,深入了解GC如何工作可 ...

  7. 廖雪峰团队最新研磨的实战宝典终终终终终终于免费了!

    众所周知,大数据技术正被广泛应用于电商.交通.工业.医疗等行业,大数据工程师已成为互联网行业炙手可热的岗位.另一方面,像月薪 20k 以上的大数据工程师,技能要求就很高,除了要熟练各种大数据框架,还要 ...

  8. 真相!没项目经验高薪就无望?

    福利!廖雪峰最新研磨的实战宝典<如何将大数据开发做到优秀>首次开放了,内容出自开课吧 vip 课程"大数据高级开发实战班",为帮助大家特殊时期职场走得更加顺畅,现决定将 ...

  9. 番茄花园 Ghost XP SP3 金秋国庆版 2013.AA0

    番茄花园 Ghost XP SP3 金秋国庆版 2013.AA0 下载地址:http://www.xiazaijidi.com/win7/fanqie/58.html 文件名称:FQ_GhostXP_ ...

最新文章

  1. 一些经典的常用ASP代码[经典简单] (2)
  2. centos8下重启网卡命令_centos8 网络配置
  3. ShopXO本地化部署安装之centeros 安装Apache2.4.6 + PHP7.0.33 + Mysql5.7.25环境
  4. Oracle ORA-01033: ORACLE initialization or shutdown in progress 错误解决办法Windows版(手贱强制重启电脑的后果)...
  5. ftp文件上传及下载工具类
  6. xx学院学员评优评奖管理系统
  7. u盘误删的文件怎么找回?帮你轻松找回
  8. 罗德里格旋转公式推导
  9. 大长今人物系列:长今的心理课——医女张德(转载)
  10. word 插入图片显示不全
  11. IOS和Android开发的一些个人感受
  12. 浏览器兼容性测试怎么做?系统测试工具及方案推荐
  13. 一般java面试考什么_JAVA面试的时候一般考什么?
  14. GPU大百科全书 第六章 谁也离不开的缓冲
  15. 【安全资讯】欧盟委员会:公司不得使用面部识别技术评判员工
  16. 没有乔布斯的MacWorld :8个瞬间
  17. Internet download manager下载外网问题
  18. Axure-9 日历选择制作
  19. Spring Data ElasticSearch的操作
  20. 有哪些读博读废了的案例?

热门文章

  1. Christopher G. Atkeson 简介
  2. mysqladmin 设置用户名初始密码报错you need the SUPER privilege for this operation
  3. 大数据打造你的变美频道——数加平台上小红唇的大数据实践
  4. js中一些常用的基本函数
  5. YII中session和cookie
  6. Java JDBC连接SQL Server2005错误:通过port 1433 连接到主机 localhost 的 TCP/IP 连接失败...
  7. RPi 2B python opencv camera demo example
  8. Java线程:线程交互
  9. [Bug]The maximum array length quota (16384) has been exceeded while reading XML data.
  10. 内建控制结构之if表达式