ehcache.xml value为list怎么使用条件查询

hibernate ehcache 查询缓存 bug?_百度知道
hibernate ehcache 查询缓存 bug?
双向关联 现通 hql查询迫切关联 查询使用查询缓存第查询显示(缓存没数据库查找)第二同查询关联数据显示(应该没缓存) bug 配置问题
请高手帮帮忙啊 <img class="word-replace" src="/api/getdecpic?picenc=0a006a家别嫌少啊
ehcache 配置 &diskstore path =&c:&#92;&#92;temp&&#47;& &defaultCache maxElementsInMemory=&10000& eternal=&false&
timeToIdleSeconds=&360&timeToLiveSeconds=&720& overflowToDisk=&true& diskPersistent=&false&&#47;&
&cache name=&org.hibernate.cache.StandardQueryCache& maxElementsInMemory=&10000& eternal=&false& timeToIdleSeconds=&3600& timeToLiveSeconds=&7200& overflowToDisk=&true&&#47;&
&cache name=&org.hibernate.cache.UpdateTimestampsCache& maxElementsInMemory=&10000& eternal=&true& overflowToDisk=&true&&#47;&查询代码
Query query = session.createQuery(hql);
query.setFirstResult(startLine);
query.setMaxResults(pageSize);
query.setCacheable(true);
return query.list();
提问者采纳
缓存存目录读写Hibernate+ehcache二级缓存技术 17:061、首先设置EhCache建立配置文件ehcache.XML默认位置class-path放src目录:<?xml version=&1.0& encoding=&UTF-8&?><ehcache> <diskStore path=&Java.io.tmpdir&/> <defaultCache maxElementsInMemory=&10000& <!-- 缓存数目 --> eternal=&false& <!-- 缓存否持久 --> overflowToDisk=&true& <!-- 否保存磁盘系统机--> timeToIdleSeconds=&300& <!-- 缓存闲置n秒销毁 --> timeToLiveSeconds=&180& <!-- 缓存存n秒销毁--> diskPersistent=&false& diskExpiryThreadIntervalSeconds= &120&/> </ehcache> 2、Hibernate配置文件设置:<!-- 设置Hibernate缓存接口类类Hibernate包 --><property name=&cache.provider_class&>org.hibernate.cache.EhCacheProvider</property>
<!-- 否使用查询缓存 --> <property name=&hibernate.cache.use_query_cache&>true</property>使用spring调用HibernatesessionFactory设置:<!--HibernateSession工厂管理 --> <bean id=&sessionFactory& class=&org.springFramework.orm.hibernate3.LocalSessionFactoryBean&> <property name=&dataSource&><ref bean=&datasource& /> </property> <property name=&hibernateProperties&> <props><prop key=&hibernate.dialect&>org.hibernate.dialect.Oracle9Dialect</prop><prop key=&connection.provider_class&>org.hibernate.connection.C3P0ConnectionProvider</prop><prop key=&hibernate.show_sql&>true</prop><prop key=&hibernate.cache.use_query_cache&>true</prop><prop key=&hibernate.cache.provider_class&>org.hibernate.cache.EhCacheProvider</prop> </props> </property> <property name=&mappingDirectoryLocations&><list> <value>/Web-INF/classes/cn/rmic/manager/hibernate/</value></list> </property> </bean> 说明:设置查询缓存hibernate缓存使用load()获单持久化象想缓存使用findall()、list()、Iterator()、createCriteria()、createQuery()等获数据结集需要设置hibernate.cache.use_query_cache true才行3、Hbm文件添加<cache usage=&read-only&/>4、需要查询缓存需要使用Query或Criteria()设置其setCacheable(true);属性5、实践真知给段测试程序功第二查询读取数据库package cn.rmic.import java.util.Limport org.hibernate.CacheMimport org.hibernate.Cimport org.hibernate.Qimport org.hibernate.Simport cn.rmic.hibernatesample.hibernate.HibernateSessionFimport cn.rmic.manager.po.Rpublic class testCacheSelectList ...{ /** *//** * @param args */ public static void main(String[] args) ...{// TODO Auto-generated method stubSession s=HibernateSessionFactory.getSession();Criteria c=s.createCriteria(Resources.class);c.setCacheable(true);List l=c.list();// Query q=s.createQuery(&From Resources r&)// .setCacheable(true) // .setCacheRegion(&frontpages&) ;// List l=q.list();Resources resources=(Resources)l.get(0);System.out.println(&-1-&+resources.getName());HibernateSessionFactory.closeSession();try ...{ Thread.sleep(5000);} catch (InterruptedException e) ...{ // TODO Auto-generated catch block e.printStackTrace();}s=HibernateSessionFactory.getSession();c=s.createCriteria(Resources.class);c.setCacheable(true);l=c.list();// q=s.createQuery(&From Resources r&).setCacheable(true) // .setCacheRegion(&frontpages&);// l=q.list();resources=(Resources)l.get(0);System.out.println(&-2-&+resources.getName());HibernateSessionFactory.closeSession(); }}
提问者评价
虽然没有 解决问题还是非常感谢
其他类似问题
按默认排序
其他1条回答
配置附近代码发看看比较,额.偶经验够呵呵,等高手.
ehcache的相关知识
您可能关注的推广
等待您来回答
下载知道APP
随时随地咨询
出门在外也不愁Hibernate ehcache配置二级缓存 - paggywong - ITeye技术网站
【转自】http://blog.csdn.net/feiyu1001/article/details/3173942
1、首先设置EhCache,建立配置文件ehcache.xml,默认的位置在class-path,可以放到你的src目录下:
&?xml version="1.0" encoding="UTF-8"?&
 &diskStore path="java.io.tmpdir"/&
  &defaultCache
   maxElementsInMemory="10000" &!-- 缓存最大数目 --&
   eternal="false" &!-- 缓存是否持久 --&
   overflowToDisk="true" &!-- 是否保存到磁盘,当系统当机时--&
   timeToIdleSeconds="300" &!-- 当缓存闲置n秒后销毁 --&
   timeToLiveSeconds="180" &!-- 当缓存存活n秒后销毁--&
   diskPersistent="false"
   diskExpiryThreadIntervalSeconds= "120"/&
&/ehcache&
2、在Hibernate配置文件中设置:
&!-- 设置Hibernate的缓存接口类,这个类在Hibernate包中 --&
&property name="cache.provider_class"&org.hibernate.cache.EhCacheProvider&/property&
 &!-- 是否使用查询缓存 --&
 &property name="hibernate.cache.use_query_cache"&true&/property&
  如果使用spring调用Hibernate的sessionFactory的话,这样设置:
  &!--HibernateSession工厂管理 --&
   &bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"&
   &property name="dataSource"&
    &ref bean="datasource" /&
   &/property&
   &property name="hibernateProperties"&
   &props&
    &prop key="hibernate.dialect"&org.hibernate.dialect.Oracle9Dialect&/prop&
&prop key="connection.provider_class"&org.hibernate.connection.C3P0ConnectionProvider&/prop&
    &prop key="hibernate.show_sql"&true&/prop&
    &prop key="hibernate.cache.use_query_cache"&true&/prop&
    &prop key="hibernate.cache.provider_class"&org.hibernate.cache.EhCacheProvider&/prop&
   &/props&
 &/property&
 &property name="mappingDirectoryLocations"&
  &list&
   &value&/WEB-INF/classes/cn/rmic/manager/hibernate/&/value&
  &/list&
 &/property&
说明一下:如果不设置“查询缓存”,那么hibernate只会缓存使用load()方法获得的单个持久化对象,如果想缓存使用findall()、
list()、Iterator()、createCriteria()、createQuery()等方法获得的数据结果集的话,就需要设置
hibernate.cache.use_query_cache true 才行
3、在Hbm文件中添加&cache usage="read-only"/&
4、如果需要“查询缓存”,还需要在使用Query或Criteria()时设置其setCacheable(true);属性
5、实践出真知,给一段测试程序,如果成功的话第二次查询时不会读取数据库
package cn.rmic.
import java.util.L
import org.hibernate.CacheM
import org.hibernate.C
import org.hibernate.Q
import org.hibernate.S
import cn.rmic.hibernatesample.hibernate.HibernateSessionF
import cn.rmic.manager.po.R
public class testCacheSelectList ...{
 public static void main(String[] args) ...{
  Session s=HibernateSessionFactory.getSession();
  Criteria c=s.createCriteria(Resources.class);
  c.setCacheable(true);
  List l=c.list();
  Resources resources=(Resources)l.get(0);
  System.out.println("-1-"+resources.getName());
  HibernateSessionFactory.closeSession();
  try ...{
   Thread.sleep(5000);
  } catch (InterruptedException e) ...{
   // TODO Auto-generated catch block
   e.printStackTrace();
  s=HibernateSessionFactory.getSession();
  c=s.createCriteria(Resources.class);
  c.setCacheable(true);
  l=c.list();
  resources=(Resources)l.get(0);
  System.out.println("-2-"+resources.getName());
  HibernateSessionFactory.closeSession();
package cn.rmic.
import java.util.L
import org.hibernate.CacheM
import org.hibernate.C
import org.hibernate.Q
import org.hibernate.S
import cn.rmic.hibernatesample.hibernate.HibernateSessionF
import cn.rmic.manager.po.R
public class testCacheSelectList ...{
 public static void main(String[] args) ...{
  Session s=HibernateSessionFactory.getSession();
  Criteria c=s.createCriteria(Resources.class);
  c.setCacheable(true);
  List l=c.list();
  Resources resources=(Resources)l.get(0);
  System.out.println("-1-"+resources.getName());
  HibernateSessionFactory.closeSession();
  try ...{
   Thread.sleep(5000);
  } catch (InterruptedException e) ...{
   // TODO Auto-generated catch block
   e.printStackTrace();
  s=HibernateSessionFactory.getSession();
  c=s.createCriteria(Resources.class);
  c.setCacheable(true);
  l=c.list();
  resources=(Resources)l.get(0);
  System.out.println("-2-"+resources.getName());
  HibernateSessionFactory.closeSession();
5.1 在Hibernate配置文件中设置:
&!-- Hibernate SessionFactory --&
&bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"&
&property name="dataSource" ref="dataSource"/&
&property name="mappingResources"&
&value&com/ouou/model/Videos.hbm.xml&/value&
&/property&
&property name="hibernateProperties"&
&prop key="hibernate.dialect"&org.hibernate.dialect.MySQLDialect&/prop&
&prop key="hibernate.current_session_context_class"&thread&/prop&
&prop key="hibernate.cglib.use_reflection_optimizer"&false&/prop&
&prop key="hibernate.query.substitutions"&true 'Y', false 'N'&/prop&
&!--add ehcache--&
&prop key="hibernate.cache.provider_class"&org.hibernate.cache.EhCacheProvider&/prop&
&prop key="hibernate.cache.use_query_cache"&false&/prop&&!-- 是否使用查询缓存 --&
&prop key="hibernate.cache.provider_configuration_file_resource_path"&/ehcache.xml&/prop&
&prop key="hibernate.show_sql"&true&/prop&
&!--&prop key="hibernate.transaction.auto_close_session"&true&/prop&--&
&prop key="connection.provider_class"&org.hibernate.connection.C3P0ConnectionProvider&/prop&
&!-- Create/update the database tables automatically when the JVM starts up
&prop key="hibernate.hbm2ddl.auto"&update&/prop& --&
&!-- Turn batching off for better error messages under PostgreSQL --&
&prop key="hibernate.jdbc.batch_size"&25&/prop&
&prop key="hibernate.connection.pool_size"&10&/prop&
&/property&
如果不设置“查询缓存”,那么hibernate只会缓存使用load()方法获得的单个持久化对象,如果想缓存使用findall()、
list()、Iterator()、createCriteria()、createQuery()等方法获得的数据结果集的话,就需要设置
hibernate.cache.use_query_cache true 才行
5.2首先设置EhCache,建立配置文件ehcache.xml,默认的位置在class-path,可以放到你的src目录下:
&!-- Sets the path to the directory where cache .data files are created.
If the path is a Java System Property it is replaced by
its value in the running VM.
The following properties are translated:
user.home - User's home directory
user.dir - User's current working directory
java.io.tmpdir - Default temp file path --&
&!--&diskStore path="java.io.tmpdir"/&--&
&diskStore path="/data/ehcache"/&
&!--Default Cache configuration. These will applied to caches programmatically created through
the CacheManager.
The following attributes are required:
maxElementsInMemory
- Sets the maximum number of objects that will be created in memory
- Sets whether elements are eternal. If eternal,
timeouts are
ignored and the element is never expired.
overflowToDisk
- Sets whether elements can overflow to disk when the in-memory cache
has reached the maxInMemory limit.
The following attributes are optional:
timeToIdleSeconds
- Sets the time to idle for an element before it expires.
i.e. The maximum amount of time between accesses before an
element expires Is only used if the element is not eternal.
Optional attribute. A value of 0 means that an Element can idle
for infinity.The default value is 0.
timeToLiveSeconds
- Sets the time to live for an element before it expires.
i.e. The maximum time between creation time and when an element
Is only used if the element is not eternal.
Optional attribute. A value of 0 means that and Element can live
for infinity.
The default value is 0.
diskPersistent
- Whether the disk store persists between restarts of the Virtual
The default value is false.
diskExpiryThreadIntervalSeconds
- The number of seconds between runs of the disk expiry thread.
The default value
is 120 seconds.
&defaultCache
maxElementsInMemory="10000"
eternal="false"
overflowToDisk="true"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
diskPersistent="false"
diskExpiryThreadIntervalSeconds="120"/&
&cache name="org.hibernate.cache.UpdateTimestampsCache" maxElementsInMemory="5000"
eternal="true" overflowToDisk="true"/&
&cache name="org.hibernate.cache.StandardQueryCache" maxElementsInMemory="5" eternal="false"
timeToLiveSeconds="120" overflowToDisk="true"/&
&cache name="userCache" maxElementsInMemory="100000" eternal="false" timeToIdleSeconds=
timeToLiveSeconds="600" overflowToDisk="false" diskPersistent="false"/&
&cache name="com.ouou.webapp.util.OuouMethodIntecepter" maxElementsInMemory="100000"
eternal="false" timeToIdleSeconds="600" timeToLiveSeconds="600" overflowToDisk="false"
diskPersistent="false"/&
&cache name="bbcode" maxElementsInMemory="100000" eternal="false" timeToIdleSeconds="600"
timeToLiveSeconds="600"
overflowToDisk="false" diskPersistent="false"/&
&cache name="com.ouou.model.Videos" maxElementsInMemory="10000"
eternal="false"
overflowToDisk="false" timeToIdleSeconds="120" timeToLiveSeconds="120" diskPersistent="false"/&
&cache name="com.ouou.model.Tags" maxElementsInMemory="10000"
eternal="false"
overflowToDisk="false" timeToIdleSeconds="120" timeToLiveSeconds="120" diskPersistent="false"/&
&/ehcache&
以com.ouou.model.Videos为例子
在Videos.hbm.xml中配置:
&class name="Videos" table="TEST" lazy="false"&
&cache usage="read-write" region="ehcache.xml中的name的属性值"/&注意:这一句需要紧跟在class标签下面,其他位置无效。
hbm文件查找cache方法名的策略:如果不指定hbm文件中的region="ehcache.xml中的name的属性值",则使用name名为com.ouou.model.Videos的cache,
如果不存在与类名匹配的cache名称,则用defaultCache。
如果Videos包含set集合,则需要另行指定其cache
例如Videos包含Tags集合,则需要
添加如下配置到ehcache.xml中
&cache name="com.ouou.model.Tags"
maxElementsInMemory="10000" eternal="false" timeToIdleSeconds="120"
timeToLiveSeconds="120" overflowToDisk="false" /&
另,针对查询缓存的配置如下:
&cache name="org.hibernate.cache.UpdateTimestampsCache"
maxElementsInMemory="5000"
eternal="true"
overflowToDisk="true"/&
&cache name="org.hibernate.cache.StandardQueryCache"
maxElementsInMemory="10000"
eternal="false"
timeToLiveSeconds="120"
overflowToDisk="true"/&
5.3 选择缓存策略依据:
usage="transactional|read-write|nonstrict-read-write|read-only" (1)/&
ehcache不支持transactional,其他三种可以支持。
read-only:无需修改, 那么就可以对其进行只读 缓存,注意,在此策略下,如果直接修改数据库,即使能够看到前台显示效果,
但是将对象修改至cache中会报error,cache不会发生作用。另:删除记录会报错,因为不能在read-only模式的对象从cache中删除。
read-write:需要更新数据,那么使用读/写缓存 比较合适,前提:数据库不可以为serializable transaction isolation level
(序列化事务隔离级别)
nonstrict-read-write:只偶尔需要更新数据(也就是说,两个事务同时更新同一记录的情况很不常见),也不需要十分严格的事务隔离,
那么比较适合使用非严格读/写缓存策略。
5.4 调试时候使用log4j的log4j.logger.org.hibernate.cache=debug,更方便看到ehcache的操作过程,主要用于调试过程,实际应用发布时候,请注释掉,以免影响性能。
5.5 使用ehcache,打印sql语句是正常的,因为query cache设置为true将会创建两个缓存区域:一个用于保存查询结果集 (
org.hibernate.cache.StandardQueryCache);另一个则用于保存最近查询的一系列表的时间戳(org.hibernate.cache.UpdateTimestampsCache)。
请注意:在查询缓存中,它并不缓存结果集中所包含的实体的确切状态;它只缓存这些实体的标识符属性的值、以及各值类型的结果。
需要将打印sql语句与最近的cache内容相比较,将不同之处修改到cache中,所以查询缓存通常会和二级缓存一起使用。
附:Ehcache的配置说明
磁盘存储配置:
用来指定缓存在磁盘上的存储位置。可以使用JavaVM环境变量(user.home, user.dir, java.io.tmpdir)
&diskStore path = "/var/apps/cache/" /&
指定CacheManagerEventListenerFactory,这个对象在缓存添加的时候会得到相应的通知
CacheManagerEventListenerFactory的属性
*class - CacheManagerEventListenerFactory的一个实现类
*properties - CacheManagerEventListenerFactory的属性值,以逗号(,)分割多个属性
如果没有实现类被指定,则系统不创建CacheManager的监听器,没有默认值
&cacheManagerEventListenerFactory class="" properties="" /&
在进行分布式缓存的应用时候需要指定CacheManagerPeerProviderFactory,
用来生成CacheManagerPeerProvider的实例,以便和集群中的其他CacheManager通信。
*class -CacheManagerPeerProviderFactory的一个实现类
*properties - CacheManagerPeerProviderFactory的属性值,以逗号(,)分割多个属性
Ehcache内建了2种基于RMI分布系统的通信策略:
*automatic - 使用多播组。在一个节点加入或者推出集群的时候自动感应
*manual - 硬编码方式
目前的awf中不考虑分布缓存
&cacheManagerPeerListenerFactory class="" properties="" /&
缓存配置。
以下属性是必须的:
name - cache的标识符,在一个CacheManager中必须唯一
maxElementsInMemory - 在内存中缓存的element的最大数目
maxElementsOnDisk - 在磁盘上缓存的element的最大数目
eternal - 设定缓存的elements是否有有效期。如果为true,timeouts属性被忽略
overflowToDisk - 设定当内存缓存溢出的时候是否将过期的element缓存到磁盘上
以下属性是可选的:
timeToIdleSeconds - 缓存element在过期前的空闲时间。默认为0,表示可空闲无限时间.
(如果指定了这个时间,是否在被hit的前超过了这个时间就会被remove?在内存缓存数目超限之前不会被remove)
timeToLiveSeconds - 缓存element的有效生命期。这个类似于timeouts,默认为0,不过期
(是否通常情况下应该大于等于timeToIdleSeconds,小于会如何?idle时间也会减小和这个数值一样)
diskPersistent - 在VM重启的时候是否持久化磁盘缓存,默认是false。
(测试一下true的情况?重载vm的时候会从磁盘进行序列化到对象)
diskExpiryThreadIntervalSeconds - 磁盘缓存的清理线程运行间隔,默认是120秒.
(测试一下0的时候会如何)
memoryStoreEvictionPolicy - 当内存缓存达到最大,有新的element加入的时候,
移除缓存中element的策略。默认是LRU,可选的有LFU和FIFO
可对缓存中的element配置诸如监听器和加载器。Ehcahe内建了一些
*cacheEventListenerFactory - 监听缓存中element的put, remove, update和expire事件
*bootstrapCacheLoaderFactory - 启动时加载缓存的element
每个用来做分布式缓存都必须设定element的事件监听器,用来在各个CacheManager节点复制消息。
Ehcache内建了基于RMI的实现 - RMICacheReplicatorFactory
&cacheEventListenerFactory class="net.sf.ehcache.distribution.RMICacheReplicatorFactory"
properties="replicateAsynchronouly=true,
replicatePuts=true,
replicateUpdates=true,
replicateUpdateViaCopy=true,
replicateRemovals=true" /&
&cache .... /&
默认的Cache配置。用来实现CacheManager.add(String cacheName)创建的缓存
&defaultCache maxElementsInMemory="10000" eternal="false"
timeToIdleSeconds="120" timeToLiveSeconds="120"
overflowToDisk="true" maxElementsOnDisk="1000000"
diskPersistent="false" diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU"
&/ehcache&
浏览: 30085 次
来自: 成都
谢谢,今天遇到了这问题
请问将Spring Bean发布成WebService 如果s ...
你好,求源码参考,谢谢。邮箱
你好!真的很厉害!
我现在也遇到这个问题
filters:{& ...
描述太简单了,楼主,共享下工程吧EHCache 施用_EHCache详细施用介绍_fork、vfork的一些有关问题__脚本百事通
稍等,加载中……
^_^请注意,有可能下面的2篇文章才是您想要的内容:
EHCache 施用
EHCache详细施用介绍
fork、vfork的一些有关问题
EHCache 施用
EHCache 使用在开发高并发量,高性能的网站应用系统时,缓存Cache起到了非常重要的作用。本文主要介绍EHCache的使用,以及使用EHCache的实践经验。
使用过多种基于Java的开源Cache组件,其中包括OSCache、JBossCache、EHCache。OSCache功能强大,使用灵活,可
用于对象缓存、Filter缓存以及在JSP中直接使用cache标签。笔者在最近的使用过程中发现,在并发量较高时,OSCache会出现线程阻塞和数
据错误,通过分析源代码发现是其内部实现的缺陷。JBossCache最大的优点是支持基于对象属性的集群同步,不过JBossCache的配置使用都较
复杂,在并发量较高的情况下,对象属性数据在集群中同步也会加大系统的开销。以上两种Cache本文仅作简单介绍,不做深入探讨。
EHCache是来自sourceforge(http://ehcache.sourceforge.net/
的开源项目,也是纯Java实现的简单、快速的Cache组件。EHCache支持内存和磁盘的缓存,支持LRU、LFU和FIFO多种淘汰算法,支持分
布式的Cache,可以作为Hibernate的缓存插件。同时它也能提供基于Filter的Cache,该Filter可以缓存响应的内容并采用
Gzip压缩提高响应速度。
一、EHCache API的基本用法
首先介绍CacheManager类。它主要负责读取配置文件,默认读取CLASSPATH下的ehcache.xml,根据配置文件创建并管理Cache对象。
// 使用默认配置文件创建CacheManager
CacheManager manager = CacheManager.create();
// 通过manager可以生成指定名称的Cache对象
Cache cache = cache = manager.getCache("demoCache");
// 使用manager移除指定名称的Cache对象
manager.removeCache("demoCache");
可以通过调用manager.removalAll()来移除所有的Cache。通过调用manager的shutdown()方法可以关闭CacheManager。
有了Cache对象之后就可以进行一些基本的Cache操作,例如:
//往cache中添加元素
Element element = new Element("key", "value");
cache.put(element);
//从cache中取回元素
Element element = cache.get("key");
element.getValue();
//从Cache中移除一个元素
cache.remove("key");
可以直接使用上面的API进行数据对象的缓存,这里需要注意的是对于缓存的对象都是必须可序列化的。在下面的篇幅中笔者还会介绍EHCache和Spring、Hibernate的整合使用。
二、配置文件
配置文件ehcache.xml中命名为demoCache的缓存配置:
&cache name="demoCache"
maxElementsInMemory="10000"
eternal="false"
overflowToDisk="true"
timeToIdleSeconds="300"
timeToLiveSeconds="600"
memoryStoreEvictionPolicy="LFU" /&
各配置参数的含义:
maxElementsInMemory:缓存中允许创建的最大对象数
eternal:缓存中对象是否为永久的,如果是,超时设置将被忽略,对象从不过期。
timeToIdleSeconds:缓存数据的钝化时间,也就是在一个元素消亡之前,两次访问时间的最大时间间隔值,这只能在元素不是永久驻留时有效,如果该值是 0 就意味着元素可以停顿无穷长的时间。
timeToLiveSeconds:缓存数据的生存时间,也就是一个元素从构建到消亡的最大时间间隔值,这只能在元素不是永久驻留时有效,如果该值是0就意味着元素可以停顿无穷长的时间。
overflowToDisk:内存不足时,是否启用磁盘缓存。
memoryStoreEvictionPolicy:缓存满了之后的淘汰算法。LRU和FIFO算法这里就不做介绍。LFU算法直接淘汰使用比较少的对象,在内存保留的都是一些经常访问的对象。对于大部分网站项目,该算法比较适用。
如果应用需要配置多个不同命名并采用不同参数的Cache,可以相应修改配置文件,增加需要的Cache配置即可。
三、利用Spring APO整合EHCache
首先,在CLASSPATH下面放置ehcache.xml配置文件。在Spring的配置文件中先添加如下cacheManager配置:
&bean id="cacheManager"
class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"&
配置demoCache:
&bean id="demoCache" class="org.springframework.cache.ehcache.EhCacheFactoryBean"&
&property name="cacheManager" ref="cacheManager" /&
&property name="cacheName"&
&value&demoCache&/value&
&/property&
接下来,写一个实现org.aopalliance.intercept.MethodInterceptor接口的拦截器类。有了拦截器就可以有选择性的
配置想要缓存的 bean 方法。如果被调用的方法配置为可缓存,拦截器将为该方法生成 cache key
并检查该方法返回的结果是否已缓存。如果已缓存,就返回缓存的结果,否则再次执行被拦截的方法,并缓存结果供下次调用。具体代码如下:
public class MethodCacheInterceptor implements MethodInterceptor,
InitializingBean {
public void setCache(Cache cache) {
this.cache =
public void afterPropertiesSet() throws Exception {
Assert.notNull(cache,
"A cache is required. Use setCache(Cache) to provide one.");
public Object invoke(MethodInvocation invocation) throws Throwable {
String targetName = invocation.getThis().getClass().getName();
String methodName = invocation.getMethod().getName();
Object[] arguments = invocation.getArguments();
String cacheKey = getCacheKey(targetName, methodName, arguments);
Element element =
synchronized (this){
element = cache.get(cacheKey);
if (element == null) {
//调用实际的方法
result = invocation.proceed();
element = new Element(cacheKey, (Serializable) result);
cache.put(element);
return element.getValue();
private String getCacheKey(String targetName, String methodName,
Object[] arguments) {
StringBuffer sb = new StringBuffer();
sb.append(targetName).append(".").append(methodName);
if ((arguments != null) && (arguments.length != 0)) {
for (int i = 0; i & arguments. i++) {
sb.append(".").append(arguments[i]);
return sb.toString();
synchronized
(this)这段代码实现了同步功能。为什么一定要同步?Cache对象本身的get和put操作是同步的。如果我们缓存的数据来自数据库查询,在没有这
段同步代码时,当key不存在或者key对应的对象已经过期时,在多线程并发访问的情况下,许多线程都会重新执行该方法,由于对数据库进行重新查询代价是
比较昂贵的,而在瞬间大量的并发查询,会对数据库服务器造成非常大的压力。所以这里的同步代码是很重要的。
接下来,继续完成拦截器和Bean的配置:
&bean id="methodCacheInterceptor" class="com.xiebing.utils.interceptor.MethodCacheInterceptor"&
&property name="cache"&
&ref local="demoCache" /&
&/property&
&bean id="methodCachePointCut" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"&
&property name="advice"&
&ref local="methodCacheInterceptor" /&
&/property&
&property name="patterns"&
&value&.*myMethod&/value&
&/property&
&bean id="myServiceBean"
class="com.xiebing.ehcache.spring.MyServiceBean"&
&bean id="myService" class="org.springframework.aop.framework.ProxyFactoryBean"&
&property name="target"&
&ref local="myServiceBean" /&
&/property&
&property name="interceptorNames"&
&value&methodCachePointCut&/value&
&/property&
中myServiceBean是实现了业务逻辑的Bean,里面的方法myMethod()的返回结果需要被缓存。这样每次对myServiceBean
的myMethod()方法进行调用,都会首先从缓存中查找,其次才会查询数据库。使用AOP的方式极大地提高了系统的灵活性,通过修改配置文件就可以实
现对方法结果的缓存,所有的对Cache的操作都封装在了拦截器的实现中。
四、CachingFilter功能
使用Spring的AOP进行整合,可以灵活的对方法的的返回结果对象进行缓存。CachingFilter功能可以对HTTP响应的内容进行缓存。这种方式缓存数据的粒度比较粗,例如缓存整张页面。它的优点是使用简单、效率高,缺点是不够灵活,可重用程度不高。
使用SimplePageCachingFilter类实现Filter缓存。该类继承自CachingFilter,有默认产生cache
key的calculateKey()方法,该方法使用HTTP请求的URI和查询条件来组成key。也可以自己实现一个Filter,同样继承
CachingFilter类,然后覆写calculateKey()方法,生成自定义的key。
在笔者参与的项目中很多页面都使用AJAX,为
保证JS请求的数据不被浏览器缓存,每次请求都会带有一个随机数参数i。如果使用SimplePageCachingFilter,那么每次生成的key
都不一样,缓存就没有意义了。这种情况下,我们就会覆写calculateKey()方法。
要使用SimplePageCachingFilter,首先在配置文件ehcache.xml中,增加下面的配置:
&cache name="SimplePageCachingFilter" maxElementsInMemory="10000" eternal="false"
overflowToDisk="false" timeToIdleSeconds="300" timeToLiveSeconds="600"
memoryStoreEvictionPolicy="LFU" /&
其中name属性必须为SimplePageCachingFilter,修改web.xml文件,增加一个Filter的配置:
&filter-name&SimplePageCachingFilter&/filter-name&
&filter-class&net.sf.ehcache.constructs.web.filter.SimplePageCachingFilter&/filter-class&
&filter-mapping&
&filter-name&SimplePageCachingFilter&/filter-name&
&url-pattern&/test.jsp&/url-pattern&
&/filter-mapping&
下面我们写一个简单的test.jsp文件进行测试,缓存后的页面每次刷新,在600秒内显示的时间都不会发生变化的。代码如下:
out.println(new Date());
CachingFilter输出的数据会根据浏览器发送的Accept-Encoding头信息进行Gzip压缩。经过笔者测试,Gzip压缩后的数据量是原来的1/4,速度是原来的4-5倍,所以缓存加上压缩,效果非常明显。
在使用Gzip压缩时,需注意两个问题:
1. Filter在进行Gzip压缩时,采用系统默认编码,对于使用GBK编码的中文网页来说,需要将操作系统的语言设置为:zh_CN.GBK,否则会出现乱码的问题。
认情况下CachingFilter会根据浏览器发送的请求头部所包含的Accept-Encoding参数值来判断是否进行Gzip压缩。虽然
IE6/7浏览器是支持Gzip压缩的,但是在发送请求的时候却不带该参数。为了对IE6/7也能进行Gzip压缩,可以通过继承
CachingFilter,实现自己的Filter,然后在具体的实现中覆写方法acceptsGzipEncoding。
具体实现参考:
protected boolean acceptsGzipEncoding(HttpServletRequest request) {
final boolean ie6 = headerContains(request, "User-Agent", "MSIE 6.0");
final boolean ie7 = headerContains(request, "User-Agent", "MSIE 7.0");
return acceptsEncoding(request, "gzip") || ie6 || ie7;
五、EHCache在Hibernate中的使用
EHCache可以作为Hibernate的二级缓存使用。在hibernate.cfg.xml中需增加如下设置:
&prop key="hibernate.cache.provider_class"&
org.hibernate.cache.EhCacheProvider
然后在Hibernate映射文件的每个需要Cache的Domain中,加入类似如下格式信息:
&cache usage="read-write|nonstrict-read-write|read-only" /&
&cache usage="read-write" /&
最后在配置文件ehcache.xml中增加一段cache的配置,其中name为该domain的类名。
&cache name="domain.class.name"
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="300"
timeToLiveSeconds="600"
overflowToDisk="false"
六、EHCache的监控
于Cache的使用,除了功能,在实际的系统运营过程中,我们会比较关注每个Cache对象占用的内存大小和Cache的命中率。有了这些数据,我们就可
以对Cache的配置参数和系统的配置参数进行优化,使系统的性能达到最优。EHCache提供了方便的API供我们调用以获取监控数据,其中主要的方法
//得到缓存中的对象数
cache.getSize();
//得到缓存对象占用内存的大小
cache.getMemoryStoreSize();
//得到缓存读取的命中次数
cache.getStatistics().getCacheHits()
//得到缓存读取的错失次数
cache.getStatistics().getCacheMisses()
? 分布式缓存
EHCache从1.2版本开始支持分布式缓存。分布式缓存主要解决集群环境中不同的服务器间的数据的同步问题。具体的配置如下:
在配置文件ehcache.xml中加入
&cacheManagerPeerProviderFactory
class="net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory"
properties="peerDiscovery=automatic, multicastGroupAddress=230.0.0.1, multicastGroupPort=4446"/&
&cacheManagerPeerListenerFactory
class="net.sf.ehcache.distribution.RMICacheManagerPeerListenerFactory"/&
另外,需要在每个cache属性中加入
&cacheEventListenerFactory class="net.sf.ehcache.distribution.RMICacheReplicatorFactory"/&
&cache name="demoCache"
maxElementsInMemory="10000"
eternal="true"
overflowToDisk="true"&
&cacheEventListenerFactory class="net.sf.ehcache.distribution.RMICacheReplicatorFactory"/&
是一个非常优秀的基于Java的Cache实现。它简单、易用,而且功能齐全,并且非常容易与Spring、Hibernate等流行的开源框架进行整
合。通过使用EHCache可以减少网站项目中数据库服务器的访问压力,提高网站的访问速度,改善用户的体验。
参考:http://u.unao./blog/static//
http://blog.csdn.net/hnzhangshilong/article/details/6689518
EHCache详细施用介绍
EHCache详细使用介绍在开发高并发量,高性能的网站应用系统时,缓存Cache起到了非常重要的作用。本文主要介绍EHCache的使用,以及使用EHCache的实践经验。
笔者使用过多种基于Java的开源Cache组件,其中包括OSCache、JBossCache、EHCache。OSCache功能强大,使用灵活,可用于对象缓存、Filter缓存以及在JSP中直接使用cache标签。笔者在最近的使用过程中发现,在并发量较高时,OSCache会出现线程阻塞和数据错误,通过分析源代码发现是其内部实现的缺陷。JBossCache最大的优点是支持基于对象属性的集群同步,不过JBossCache的配置使用都较复杂,在并发量较高的情况下,对象属性数据在集群中同步也会加大系统的开销。以上两种Cache本文仅作简单介绍,不做深入探讨。
EHCache是来自sourceforge(http://ehcache.sourceforge.net/)的开源项目,也是纯Java实现的简单、快速的Cache组件。EHCache支持内存和磁盘的缓存,支持LRU、LFU和FIFO多种淘汰算法,支持分布式的Cache,可以作为 Hibernate的缓存插件。同时它也能提供基于Filter的Cache,该Filter可以缓存响应的内容并采用Gzip压缩提高响应速度。EHCache API的基本用法
首先介绍CacheManager类。它主要负责读取配置文件,默认读取CLASSPATH下的ehcache.xml,根据配置文件创建并管理Cache对象。
// 使用默认配置文件创建CacheManager
CacheManager manager = CacheManager.create();
// 通过manager可以生成指定名称的Cache对象
Cache cache = cache = manager.getCache("demoCache");
// 使用manager移除指定名称的Cache对象
manager.removeCache("demoCache");可以通过调用manager.removalAll()来移除所有的Cache。通过调用manager的shutdown()方法可以关闭CacheManager。
有了Cache对象之后就可以进行一些基本的Cache操作,例如:
//往cache中添加元素Element element = new Element("key", "value");cache.put(element);//从cache中取回元素Element element = cache.get("key");element.getValue();//从Cache中移除一个元素cache.remove("key");可以直接使用上面的API进行数据对象的缓存,这里需要注意的是对于缓存的对象都是必须可序列化的。在下面的篇幅中笔者还会介绍EHCache和Spring、Hibernate的整合使用。配置文件
配置文件ehcache.xml中命名为demoCache的缓存配置:
&cache name="demoCache"
maxElementsInMemory="10000"
eternal="false"
overflowToDisk="true"
timeToIdleSeconds="300"
timeToLiveSeconds="600"
memoryStoreEvictionPolicy="LFU" /&
各配置参数的含义:maxElementsInMemory:缓存中允许创建的最大对象数eternal:缓存中对象是否为永久的,如果是,超时设置将被忽略,对象从不过期。timeToIdleSeconds:缓存数据的钝化时间,也就是在一个元素消亡之前,两次访问时间的最大时间间隔值, 这只能在元素不是永久驻留时有效,如果该值是 0 就意味着元素可以停顿无穷长的时间。timeToLiveSeconds:缓存数据的生存时间,也就是一个元素从构建到消亡的最大时间间隔值,这只能在元素不是永久驻留时有效,如果该值是0就意味着元素可以停顿无穷长的时间。overflowToDisk:内存不足时,是否启用磁盘缓存。memoryStoreEvictionPolicy:缓存满了之后的淘汰算法。LRU和FIFO算法这里就不做介绍。LFU算法直接淘汰使用比较少的对象,在内存保留的都是一些经常访问的对象。对于大部分网站项目,该算法比较适用。如果应用需要配置多个不同命名并采用不同参数的Cache,可以相应修改配置文件,增加需要的Cache配置即可。利用Spring APO整合EHCache
首先,在CLASSPATH下面放置ehcache.xml配置文件。在Spring的配置文件中先添加如下cacheManager配置:&bean id="cacheManager"
class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"&&/bean&配置demoCache:&bean id="demoCache" class="org.springframework.cache.ehcache.EhCacheFactoryBean"&
&property name="cacheManager" ref="cacheManager" /&
&property name="cacheName"&
&value&demoCache&/value&
&/property&&/bean&接下来,写一个实现org.aopalliance.intercept.MethodInterceptor接口的拦截器类。有了拦截器就可以有选择性的配置想要缓存的 bean 方法。如果被调用的方法配置为可缓存,拦截器将为该方法生成 cache key 并检查该方法返回的结果是否已缓存。如果已缓存,就返回缓存的结果,否则再次执行被拦截的方法,并缓存结果供下次调用。具体代码如下:public class MethodCacheInterceptor implements MethodInterceptor,
InitializingBean {
* 设置缓存名
public void setCache(Cache cache) {
this.cache =
* 检查是否提供必要参数。
public void afterPropertiesSet() throws Exception {
Assert.notNull(cache,
"A cache is required. Use setCache(Cache) to provide one.");
* 如果某方法可被缓存就缓存其结果,方法的返回结果必须是可序列化的(Serializable)
public Object invoke(MethodInvocation invocation) throws Throwable {
String targetName = invocation.getThis().getClass().getName();
String methodName = invocation.getMethod().getName();
Object[] arguments = invocation.getArguments();
String cacheKey = getCacheKey(targetName, methodName, arguments);
Element element =
synchronized (this){
element = cache.get(cacheKey);
if (element == null) {
//调用实际的方法
result = invocation.proceed();
element = new Element(cacheKey, (Serializable) result);
cache.put(element);
return element.getValue();
* 生成CacheKey: targetName.methodName.argument0.argument1...
private String getCacheKey(String targetName, String methodName,
Object[] arguments) {
StringBuffer sb = new StringBuffer();
sb.append(targetName).append(".").append(methodName);
if ((arguments != null) && (arguments.length != 0)) {
for (int i = 0; i & arguments. i++) {
sb.append(".").append(arguments[i]);
return sb.toString();
}}synchronized (this)这段代码实现了同步功能。为什么一定要同步?Cache对象本身的get和put操作是同步的。如果我们缓存的数据来自数据库查询,在没有这段同步代码时,当key不存在或者key对应的对象已经过期时,在多线程并发访问的情况下,许多线程都会重新执行该方法,由于对数据库进行重新查询代价是比较昂贵的,而在瞬间大量的并发查询,会对数据库服务器造成非常大的压力。所以这里的同步代码是很重要的。
接下来,继续完成拦截器和Bean的配置:&bean id="methodCacheInterceptor" class="com.xiebing.utils.interceptor.MethodCacheInterceptor"&
&property name="cache"&
&ref local="demoCache" /&
&/property&&/bean&&bean id="methodCachePointCut" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"&
&property name="advice"&
&ref local="methodCacheInterceptor" /&
&/property&
&property name="patterns"&
&value&.*myMethod&/value&
&/property&&/bean&
&bean id="myServiceBean"
class="com.xiebing.ehcache.spring.MyServiceBean"&&/bean&&bean id="myService" class="org.springframework.aop.framework.ProxyFactoryBean"&
&property name="target"&
&ref local="myServiceBean" /&
&/property&
&property name="interceptorNames"&
&value&methodCachePointCut&/value&
&/property&&/bean&其中myServiceBean是实现了业务逻辑的Bean,里面的方法myMethod()的返回结果需要被缓存。这样每次对 myServiceBean的myMethod()方法进行调用,都会首先从缓存中查找,其次才会查询数据库。使用AOP的方式极大地提高了系统的灵活性,通过修改配置文件就可以实现对方法结果的缓存,所有的对Cache的操作都封装在了拦截器的实现中。 CachingFilter功能使用Spring的AOP进行整合,可以灵活的对方法的的返回结果对象进行缓存。CachingFilter功能可以对HTTP响应的内容进行缓存。这种方式缓存数据的粒度比较粗,例如缓存整张页面。它的优点是使用简单、效率高,缺点是不够灵活,可重用程度不高。
EHCache使用SimplePageCachingFilter类实现Filter缓存。该类继承自CachingFilter,有默认产生 cache key的calculateKey()方法,该方法使用HTTP请求的URI和查询条件来组成key。也可以自己实现一个Filter,同样继承 CachingFilter类,然后覆写calculateKey()方法,生成自定义的key。在笔者参与的项目中很多页面都使用AJAX,为保证JS请求的数据不被浏览器缓存,每次请求都会带有一个随机数参数i。如果使用 SimplePageCachingFilter,那么每次生成的key都不一样,缓存就没有意义了。这种情况下,我们就会覆写 calculateKey()方法。要使用SimplePageCachingFilter,首先在配置文件ehcache.xml中,增加下面的配置:&cache name="SimplePageCachingFilter" maxElementsInMemory="10000" eternal="false"
overflowToDisk="false" timeToIdleSeconds="300" timeToLiveSeconds="600"
memoryStoreEvictionPolicy="LFU" /&其中name属性必须为SimplePageCachingFilter,修改web.xml文件,增加一个Filter的配置:&filter&
&filter-name&SimplePageCachingFilter&/filter-name&
&filter-class&net.sf.ehcache.constructs.web.filter.SimplePageCachingFilter&/filter-class&&/filter&&filter-mapping&
&filter-name&SimplePageCachingFilter&/filter-name&
&url-pattern&/test.jsp&/url-pattern&&/filter-mapping&下面我们写一个简单的test.jsp文件进行测试,缓存后的页面每次刷新,在600秒内显示的时间都不会发生变化的。代码如下:&%out.println(new Date());%&CachingFilter输出的数据会根据浏览器发送的Accept-Encoding头信息进行Gzip压缩。经过笔者测试,Gzip压缩后的数据量是原来的1/4,速度是原来的4-5倍,所以缓存加上压缩,效果非常明显。在使用Gzip压缩时,需注意两个问题:1.
Filter在进行Gzip压缩时,采用系统默认编码,对于使用GBK编码的中文网页来说,需要将操作系统的语言设置为:zh_CN.GBK,否则会出现乱码的问题。2.
默认情况下CachingFilter会根据浏览器发送的请求头部所包含的Accept-Encoding参数值来判断是否进行Gzip压缩。虽然 IE6/7浏览器是支持Gzip压缩的,但是在发送请求的时候却不带该参数。为了对IE6/7也能进行Gzip压缩,可以通过继承 CachingFilter,实现自己的Filter,然后在具体的实现中覆写方法acceptsGzipEncoding。具体实现参考:protected boolean acceptsGzipEncoding(HttpServletRequest request) {
final boolean ie6 = headerContains(request, "User-Agent", "MSIE 6.0");
final boolean ie7 = headerContains(request, "User-Agent", "MSIE 7.0");
return acceptsEncoding(request, "gzip") || ie6 || ie7;}EHCache在Hibernate中的使用EHCache可以作为Hibernate的二级缓存使用。在hibernate.cfg.xml中需增加如下设置:&prop key="hibernate.cache.provider_class"&
org.hibernate.cache.EhCacheProvider&/prop&然后在Hibernate映射文件的每个需要Cache的Domain中,加入类似如下格式信息:&cache usage="read-write|nonstrict-read-write|read-only" /&比如:&cache usage="read-write" /&最后在配置文件ehcache.xml中增加一段cache的配置,其中name为该domain的类名。&cache name="domain.class.name"maxElementsInMemory="10000"eternal="false"timeToIdleSeconds="300"timeToLiveSeconds="600"overflowToDisk="false"/&
EHCache的监控
对于Cache的使用,除了功能,在实际的系统运营过程中,我们会比较关注每个Cache对象占用的内存大小和Cache的命中率。有了这些数据,我们就可以对Cache的配置参数和系统的配置参数进行优化,使系统的性能达到最优。EHCache提供了方便的API供我们调用以获取监控数据,其中主要的方法有://得到缓存中的对象数cache.getSize();//得到缓存对象占用内存的大小cache.getMemoryStoreSize();//得到缓存读取的命中次数cache.getStatistics().getCacheHits()//得到缓存读取的错失次数cache.getStatistics().getCacheMisses()分布式缓存EHCache从1.2版本开始支持分布式缓存。分布式缓存主要解决集群环境中不同的服务器间的数据的同步问题。具体的配置如下:在配置文件ehcache.xml中加入&cacheManagerPeerProviderFactory
class="net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory"
properties="peerDiscovery=automatic, multicastGroupAddress=230.0.0.1, multicastGroupPort=4446"/&&cacheManagerPeerListenerFactory
class="net.sf.ehcache.distribution.RMICacheManagerPeerListenerFactory"/&另外,需要在每个cache属性中加入&cacheEventListenerFactory class="net.sf.ehcache.distribution.RMICacheReplicatorFactory"/&例如:&cache name="demoCache"
maxElementsInMemory="10000"
eternal="true"
overflowToDisk="true"&
&cacheEventListenerFactory class="net.sf.ehcache.distribution.RMICacheReplicatorFactory"/&&/cache&总结
EHCache是一个非常优秀的基于Java的Cache实现。它简单、易用,而且功能齐全,并且非常容易与Spring、Hibernate等流行的开源框架进行整合。通过使用EHCache可以减少网站项目中数据库服务器的访问压力,提高网站的访问速度,改善用户的体验。
fork、vfork的一些有关问题
fork、vfork的一些问题
在《UNIX环境高级编程》一书的第八章中,有一道课后习题如下:
回忆图7-3典型的存储空间布局。由于对应于每个函数调用的栈帧通常存储在栈中,并在调用 vfork后,子进程运行在父进程的地址空间中,如果不是在main函数中而是在另一个函数中调用vfork,以后子进程从该函数返回时,将会发生什么情况?
作者Rich Stevens是一位大师,留下这么一题必有其深意,于是结合《深入理解计算机系统》中的知识,写了个程序验证了下,受益良多。
首先回忆下程序运行的栈帧结构(见下图):
从图中可知,如果一个函数调用用了另外一个函数,那么被调用者的栈帧则会被压入栈顶被设置为“当前帧”,首先执行被调用者,执行完成后,调用者的栈帧被弹出程序栈,然后从“返回地址”返回到调用者的地址空间中。
于是猜想,如果在main函数中,调用了一个函数foo,则“当前帧”为foo的栈帧,这时,若调用vfork创建一个子进程,那么根据vfork的语义,子进程不会完全复制父进程的地址空间,它会在父进程的地址空间中运行(这也是为什么vfork能保证子进程先运行,而fork不能保证。因为vfork创建的子进程是与父进程共享地址空间,为了避免竞争,所以就让子进程先运行,而父进程后运行;而fork创建的子进程是父进程的副本,所以不会带来竞争问题,谁先谁后也就无所谓了),所以它共享的是“当前帧”的地址空间,因此当子进程返回时,只会改变foo的数据,而不会改变main栈帧中的数据。
下面就来写个程序验证一下:
view plain#include &stdio.h&
#include &unistd.h&
#include &sys/types.h&
int glob = 88;
//a global var
void foo(int);
int main(int argc,char *arg[])
int var = 100;
//a local var in main
if(printf("In main var:%d
glob:%d pid:%d/n",var,glob,getpid())&0)
perror("main printf");
void foo(int var)
int loc = 66;
//a local var in foo
printf("Before vfork/n");
if((pid = vfork())&0)
perror("vfork");
else if(pid == 0)
//child process
printf("pid:%d/n",getpid());
/*parent process continues here*/
printf("In foo var:%d
pid:%d/n",var,glob,loc,getpid());
运行此程序,得到结果为(见下图):
果然,可以看到在foo和main中,进程号都是一样的,也就说明foo和main在同一进程中。但是各个变量的值却有差异:在foo返回后mian函数中的局部变量var依然是初始值,并没有增加,推其原因,就是因为子进程共享的是foo的栈帧数据,而非main函数的栈帧,所以自然也就不会改变main栈帧中的数据。
书中正文中说:子进程不会完全复制父进程的地址空间,它会在父进程的地址空间中运行。因此可以进一步得出一个结论:vfork创建的子进程,共享的是父进程当前栈帧的地址空间。
原文链接:http://blog.csdn.net/litingli/article/details/5122853
本文是涉及到fork,vfork,exec和进程通信,父子进程数据共享这几个方面的讨论。
Linux中,创建进程的方式,只有一种,那就是调用fork(或者vfork)。 当然,系统的交换进程,init进程除外,它们是操作系统自举时用特殊方式创建的最初的进程。
举个例子,父进程A 创建子进程B 后,进程B 就拥有了A 的所有数据(包括父进程的数据空间、堆和栈)的相同副本,并且共享代码片段(正文段)。父子进程的运行路线仅靠fork的返回值来区分。子进程从调用fork 之后的代码行继续执行,这点很重要。它意味着,之前的代码只有父进程会执行,fork之后的代码靠其返回值导向不同的流向。当然,如果fork 外部嵌套了结构控制语句,情况可能会更麻烦一点。这种情况下,父子进程可能仍有机会在跳出fork语句块之后,执行一段相同的代码。
我们之所以用fork 调用,大多数情况是在子进程中调用exec 函数来启动另一个新的程序。即运行另一个可能是其他人所编写的程序(含有main函数的完整程序)。这时,子进程B 若调用了exec,那么就意味着进程B 被kill了,进程B 从进程A 那里继承的代码从调用exec 那行开始都无效,所有的数据也被清空。所以,在调用exec 后所编写的代码都是毫无意义的。唯一保留的是B的pid号,exec 所调用的那个程序会继承B 的pid 继续执行,直到结束。
有了上面的这些概念,下面就开始说说vfork和父子进程的数据共享。这是我现在所关心的。首先,vfork产生的子进程共享父进程的所有地址空间(无论是正文段还是数据段),这就是程序中我使用了vfork的重要原因。因为,你要知道,若不是这样,父子进程之间的通信和数据共享的代码就又够我折腾一阵子了。不用vfork的话,我可能就不得不借助于管道通信,共享内存,乃至多线程的编写来解决这个问题。另外,vfork和fork之间的另一个区别是:vfork保证子进程先运行,在它调用exec或exit之后父进程才可能被调度运行(exec之后父进程还是可以运行的)。有一点要提醒的是,网上有人说,在Linux中vfork已经丧失了其功能,变得和fork功能一样,还好,在我实验的RedHat 和Debian版本中vfork 还保留着共享父进程数据的能力。(实际上,UNIX系统都还保留着两者的不同之处)
这篇文章是自己在编写一个Linux小程序时,遇到问题有感而发的。
vfork用于创建一个新进程,而该新进程的目的是exec一个新进程,vfork和fork一样都创建一个子进程,但是它并不将父进程的地址空间完全复制到子进程中,不会复制页表。因为子进程会立即调用exec,于是也就不会存放该地址空间。不过在子进程中调用exec或exit之前,他在父进程的空间中运行。
为什么会有vfork,因为以前的fork当它创建一个子进程时,将会创建一个新的地址空间,并且拷贝父进程的资源,而往往在子进程中会执行exec调用,这样,前面的拷贝工作就是白费力气了,这种情况下,聪明的人就想出了vfork,它产生的子进程刚开始暂时与父进程共享地址空间(其实就是线程的概念了),因为这时候子进程在父进程的地址空间中运行,所以子进程不能进行写操作,并且在儿子“霸占”着老子的房子时候,要委屈老子一下了,让他在外面歇着(阻塞),一旦儿子执行了exec或者exit后,相当于儿子买了自己的房子了,这时候就相当于分家了(子进程有了自己的地址空间,不再用父进程的地址空间)。
vfork和fork之间的另一个区别是: vfork保证子进程先运行,在她调用exec或exit之后父进程才可能被调度运行。如果在调用这两个函数之前子进程依赖于父进程的进一步动作,则会导致死锁。
由此可见,这个系统调用是用来启动一个新的应用程序。其次,子进程在vfork()返回后直接运行在父进程的栈空间,并使用父进程的内存和数据。这意味着子进程可能破坏父进程的数据结构或栈,造成失败。
为了避免这些问题,需要确保一旦调用vfork(),子进程就不从当前的栈框架中返回,并且如果子进程改变了父进程的数据结构就不能调用exit函数。子进程还必须避免改变全局数据结构或全局变量中的任何信息,因为这些改变都有可能使父进程不能继续。
通常,如果应用程序不是在fork()之后立即调用exec(),就有必要在fork()被替换成vfork()之前做仔细的检查。
用fork函数创建子进程后,子进程往往要调用一种exec函数以执行另一个程序,当进程调用一种exec函数时,该进程完全由新程序代换,而新程序则从其main函数开始执行,因为调用exec并不创建新进程,所以前后的进程id 并未改变,exec只是用另一个新程序替换了当前进程的正文,数据,堆和栈段。
原文链接:/Linux/01.htm
特别参考: http://alexrenguoly./blog/static/6/
如果您想提高自己的技术水平,欢迎加入本站官方1号QQ群:&&,&&2号QQ群:,在群里结识技术精英和交流技术^_^
本站联系邮箱:

我要回帖

更多关于 ehcache 使用 的文章

 

随机推荐