2021SC@SDUSC
store-impl文件夹分析
CocoonStoreJanitor.java
1、总结
CocoonStoreJanitor 类只是继承 StoreJanitorImpl 以覆盖使用 Cocoon RunnableManager 创建后台线程的 start 方法
2、实例字段
//要使用的线程池的名称。 默认为“守护进程”
private String threadPool = THREAD_POOL;
//在启动时忽略内存突发的标志
private boolean m_firstRun = true;
//在启动时忽略内存突发的标志
private boolean m_secondRun = false;
3、方法:
public void setThreadPool(String threadPool)
- 设置要使用的线程池的名称。
- 如果未指定,则默认为“守护进程”
public void run() {
// 忽略前两次调用中的内存突发
if (m_firstRun || m_secondRun) {
super.inUse = super.memoryInUse();
m_secondRun = m_firstRun;
m_firstRun = false;
}
super.checkMemory();
// 重新启动
relaunch(super.interval);
}
- 当使用实现接口 Runnable 的对象创建线程时,启动线程会导致在单独执行的线程中调用对象的 run 方法,此处用于“检查器”线程循环
public void start()
- 使用 RunnableManager 中的默认线程启动此实例
private void relaunch(final long delay)
- 是否使用来自 RunnableManager 的默认线程延迟(重新)启动此实例并延迟
- 参数delay:在下次运行之前应用的延迟
Ehcache.xml
<diskStore path="${diskstorepath}"/>
- 设置创建缓存 .data 文件的目录的路径。
- 如果路径是 Java 系统属性,则它会替换为正在运行的 VM 中的值。
<defaultCache
maxElementsInMemory="10000"
eternal="true"
timeToIdleSeconds="0"
timeToLiveSeconds="0"
overflowToDisk="true"
diskPersistent="true"
diskExpiryThreadIntervalSeconds="120"
/>
- 默认缓存配置。这些将应用于通过 CacheManager 以编程方式创建的缓存
- 必有属性:
maxElementsInMemory
——设置将在永久内存中创建的最大对象数
eternal
——设置元素是否永恒。如果是永恒的,则忽略超时并且元素永远不会过期
overflowToDisk
——设置当内存缓存达到maxInMemory
限制时元素是否可以溢出到磁盘 - 可选属性:
timeToIdleSeconds
——设置元素在到期之前的空闲时间。即元素到期之前访问之间的最大时间量仅在元素不是永恒的情况下使用。值为0意味着 Element 可以无限空闲。默认值为0
timeToLiveSeconds
——设置元素在过期之前的生存时间。即创建时间和元素过期之间的最长时间。仅在元素不是永恒元素时使用。值为0表示元素可以无限存在。默认值为0
diskPersistent
——磁盘存储是否在虚拟机重新启动之间持续存在。默认值为假
diskExpiryThreadIntervalSeconds
——磁盘到期线程运行之间的秒数。默认值是120s
StoreJanitorImpl.java
1、总结
这个类是 StoreJanitor 的实现。 Store 类可以注册到 StoreJanitor。当内存太低时,StoreJanitor 会释放已注册的缓存,直到内存正常
实现了StoreJanitor, Runnable接口
2、主要属性
- 清洗算法
//已注册的缓存循环通过,并且每次出现内存不足的情况时,其中一个已注册的缓存都会从中释放对象
private static final String ALG_ROUND_ROBIN = "round-robin";
//每次出现内存不足的情况时,所有已注册的存储都会从中删除对象
private static final String ALG_ALL_STORES = "all-stores";
- 注意:这个类不需要是可启动的。 这允许在内存第一次注册 itsefl 时懒惰地创建管理员线程
//JVM 中应始终空闲的字节数(默认值:1mb)
private static final int FREE_MEMORY = 1024 * 1024;
//JVM 内存消耗的最大可能大小(默认值:64mb)
private static final int HEAP_SIZE = 66600000;
//运行清理线程的频率(秒)(默认值:10s)
private static final int CLEAN_UP_THREAD_INTERVAL = 10 * 1000;
//启用自适应算法来确定线程间隔(默认值:false)当为真时,cleanupthreadinterval 定义最大清理间隔。然后根据内存填充率确定清理间隔:内存填充越快,剩余的空闲内存越少,清理时间越短。
private static final boolean ADAPTIVE_THREAD_INTERVAL = false;
//当内存不足 (1-100) 时要释放的存储部分。 (默认:10%)
private static final int PERCENT_TO_FREE = 10;
- 配置参数
private int minFreeMemory = FREE_MEMORY;
private int maxHeapSize = HEAP_SIZE;
private int threadInterval = CLEAN_UP_THREAD_INTERVAL;
private int minThreadInterval = 500;
private boolean adaptiveThreadInterval = ADAPTIVE_THREAD_INTERVAL;
private int priority = -1;
private String freeingAlgorithm = ALG_ROUND_ROBIN;
private double fraction = PERCENT_TO_FREE / 100.0D;
- 其他
//默认情况下,我们使用这个类的记录器
private Log logger = LogFactory.getLog(getClass());
//判断是否需要在低内存上调用gc
protected boolean invokeGC;
//sleep()之前使用的内存量。必须最初调用memoryInUse()设置一个合理的值
protected long inUse;
//下一次检查器运行的计算延迟(以毫秒为单位)
protected long interval = Long.MAX_VALUE;
//已用内存变化率(以每秒字节数为单位)
private long maxRateOfChange = 1;
3、方法
public void setFreeMemory(int freeMemory)
- jvm 中可用的内存数,如果未指定,则默认为 1Mb
public void setHeapSize(int heapSize)
- 最大 jvm 可以消耗的内存数,如果未指定,则默认为 66600000 字节
Sun的JVM的默认最大堆大小是(几乎)64Mb,可以通过指定 -Xmx 命令行参数来增加
public void setPercentToFree(double percentToFree)
- 在内存不足的情况下,应该丢弃存储元素的比例,如果未指定,则默认为10%
public void setInvokeGC(boolean invokeGC)
- 判断是否应该在内存不足时调用垃圾收集器,如果未指定,默认为 false
public void setThreadPriority(int threadPriority)
- 设置清理线程的优先级,此属性仅由管理员的旧实现使用,新实现使用集中配置的线程池
protected void checkMemory() {
if (getAdaptiveThreadInterval()) {
// 监视使用中的堆的变化率
long change = memoryInUse() - inUse;
long rateOfChange = longDiv(change * 1000, interval); // bps.
if (maxRateOfChange < rateOfChange) {
maxRateOfChange = (maxRateOfChange + rateOfChange) / 2;
}
if (getLogger().isDebugEnabled()) {
getLogger().debug("Waking after " + interval + "ms, in use change "
+ change + "b to " + memoryInUse() + "b, rate "
+ rateOfChange + "b/sec, max rate " + maxRateOfChange + "b/sec");
}
}
//使用的内存量大于堆大小
if (memoryLow()) {
if (this.invokeGC) {
freePhysicalMemory();
}
synchronized (this) {
if (!this.invokeGC
|| (memoryLow() && getStoreList().size() > 0)) {
freeMemory();
setIndex(getIndex() + 1);
}
}
}
if (getAdaptiveThreadInterval()) {
// 根据变化率和剩余可用内存计算睡眠间隔
interval = minTimeToFill(maxRateOfChange) * 1000 / 2;
if (interval > this.threadInterval) {
interval = this.threadInterval;
} else if (interval < this.minThreadInterval) {
interval = this.minThreadInterval;
}
inUse = memoryInUse();
} else {
interval = this.threadInterval;
}
}
- “检查器”线程检查 jvm 中的内存是否不足
- 调用
memoryLow()
判断JVM中内存是否不足,若invokeGC(是否应该在低内存上调用 gc的标志位)为true,调用gc()
运行垃圾收集器。 调用此方法表明 Java 虚拟机将努力回收未使用的对象,以使它们当前占用的内存可用于快速重用。若invokeGC为false,调用freeMemory()
根据所选算法从内存中自由配置的对象百分比
private void freeMemory() {
try {
// 选择了什么算法?
// 选项 1:缩小所有注册内存的规模
if (this.freeingAlgorithm.equals(ALG_ALL_STORES)) {
for (Iterator i = iterator(); i.hasNext(); ) {
removeStoreObjects((Store) i.next());
}
return;
}
// 选项 2:默认为循环
// 确定这次要清除的内存
if (getIndex() < getStoreList().size()) {
if (getIndex() == -1) {
setIndex(0);
}
} else {
//商店列表已更改(一个或多个商店已被删除)
if (getLogger().isDebugEnabled()) {
getLogger().debug("Restarting from the beginning");
}
setIndex(0);
}
// 从此内存中删除对象
removeStoreObjects((Store) getStoreList().get(getIndex()));
} catch (Exception e) {
getLogger().error("Error in freeMemory()", e);
} catch (OutOfMemoryError e) {
getLogger().error("OutOfMemoryError in freeMemory()");
}
}
- 根据所选算法从存储中自由配置的对象百分比
- 调用
removeStoreObjects(Store store)
从提供的存储中清除配置的对象数量(先计算要从存储中释放多少对象,并将其从当前存储中删除)
参数store:从中释放对象的 Store
private int calcToFree(Store store)
- 此方法计算要从内存中释放的项目数量
public Iterator iterator()
- 此方法返回每个注册商店的 java.util.Iterator
- 返回的迭代器是快速失败的:如果在创建迭代器后的任何时间对列表进行了结构修改,无论以任何方式,迭代器都会抛出 ConcurrentModificationException。 因此,面对并发修改,迭代器快速而干净地失败,而不是冒着在未来不确定的时间出现任意、非确定性行为的风险
MRUMemoryStore.java
1、总结
此类为请求的文档提供缓存算法。 它结合了 HashMap 和 LinkedList 来创建所谓的 MRU(最近使用)缓存
改编自 org.apache.excalibur.store.impl.MRUMemoryStore
继承自store
2、方法
public void setMaxObjects(int maxobjects)
- 指示将在缓存中保留多少对象,当达到 maxobjects 的数量时,缓存中的最后一个对象将被抛出(默认:100 个对象)
public synchronized void store(Object key, Object value)
- 将给定的对象存储在持久状态。 由调用者确保密钥在不同的 JVM 执行中具有持久状态
public synchronized void hold(Object key, Object value) {
if (getLogger().isDebugEnabled()) {
getLogger().debug("Holding object in memory:");
getLogger().debug(" key: " + key);
getLogger().debug(" value: " + value);
}
//首先测试是否达到了缓存中的最大值
while (this.mrulist.size() >= this.maxObjects) {
//达到堆大小,删除最后一个元素
free();
}
//将新对象放在缓存中,当然是在顶部
this.cache.put(key, value);
this.mrulist.remove(key);
this.mrulist.addFirst(key);
}
- 该方法将请求的对象保存在一个 HashMap 中,并结合一个 LinkedList 来创建 MRU。 如果配置,它还会将对象存储到文件系统中
- 参数key:要存储的对象的键
参数value:要存储的对象
public synchronized void free()
- 释放此存储使用的一些快速内存。 它删除存储中的最后一个元素
public synchronized int size()
- 返回存储中对象的计数,如果无法获得,则返回 -1
public synchronized void store(Object key, Object value)
- 将给定的对象存储在持久状态。 由调用者确保密钥在不同的 JVM 执行中具有持久状态