参考自:http://www.androidstar.cn/java%E5%AD%A6%E4%B9%A0%E6%95%99%E7%A8%8B%E4%B9%8Breference%E8%AF%A6%E8%A7%A3/ JAVA引用体系中我们最熟悉的就是强引用类型,如 A a= new A();这是我们经常说的强引用StrongReference,jvm gc时会检测对象是否存在强引用,如果存在由根对象对其有传递的强引用,则不会对其进行回收,即使内存不足抛出OutOfMemoryError。
boolean enqueue(Reference extends T> r) { /* Called only by Reference class */
synchronized (lock) {
// Check that since getting the lock this reference hasn’t already been
// enqueued (and even then removed)
ReferenceQueue> queue = r.queue;
if ((queue == NULL) || (queue == ENQUEUED)) {
return false;
}
assert queue == this;
r.queue = ENQUEUED;
r.next = (head == null) ? r : head;
head = r;
queueLength++;
if (r instanceof FinalReference) {
sun.misc.VM.addFinalRefCount(1);
}
lock.notifyAll();
return true;
}
}
Reference与ReferenceQueue之间是如何工作的呢?
/* List of References waiting to be enqueued. The collector adds
* References to this list, while the Reference-handler thread removes
* them. This list is protected by the above lock object. The
* list uses the discovered field to link its elements.
*/
private static Reference pending = null;
/**
* Try handle pending {@link Reference} if there is one.
* Return {@code true} as a hint that there might be another
* {@link Reference} pending or {@code false} when there are no more pending
* {@link Reference}s at the moment and the program can do some other
* useful work instead of looping.
*
* @param waitForNotify if {@code true} and there was no pending
* {@link Reference}, wait until notified from VM
* or interrupted; if {@code false}, return immediately
* when there is no pending {@link Reference}.
* @return {@code true} if there was a {@link Reference} pending and it
* was processed, or we waited for notification and either got it
* or thread was interrupted before being notified;
* {@code false} otherwise.
*/
static boolean tryHandlePending(boolean waitForNotify) {
Reference r;
Cleaner c;
try {
synchronized (lock) {
if (pending != null) {
r = pending;
// 'instanceof' might throw OutOfMemoryError sometimes
// so do this before un-linking 'r' from the 'pending' chain...
c = r instanceof Cleaner ? (Cleaner) r : null;
// unlink 'r' from 'pending' chain
pending = r.discovered;
r.discovered = null;
} else {
// The waiting on the lock may cause an OutOfMemoryError
// because it may try to allocate exception objects.
if (waitForNotify) {
lock.wait();
}
// retry if waited
return waitForNotify;
}
}
} catch (OutOfMemoryError x) {
// Give other threads CPU time so they hopefully drop some live references
// and GC reclaims some space.
// Also prevent CPU intensive spinning in case 'r instanceof Cleaner' above
// persistently throws OOME for some time...
Thread.yield();
// retry
return true;
} catch (InterruptedException x) {
// retry
return true;
}
// Fast path for cleaners
if (c != null) {
c.clean();
return true;
}
ReferenceQueue super Object> q = r.queue;
if (q != ReferenceQueue.NULL) q.enqueue(r);
return true;
}
static {
ThreadGroup tg = Thread.currentThread().getThreadGroup();
for (ThreadGroup tgn = tg;
tgn != null;
tg = tgn, tgn = tg.getParent());
Thread handler = new ReferenceHandler(tg, "Reference Handler");
/* If there were a special system-only priority greater than
* MAX_PRIORITY, it would be used here
*/
handler.setPriority(Thread.MAX_PRIORITY);
handler.setDaemon(true);
handler.start();
// provide access in SharedSecrets
SharedSecrets.setJavaLangRefAccess(new JavaLangRefAccess() {
@Override
public boolean tryHandlePendingReference() {
return tryHandlePending(false);
}
});
}
/**
* 为了确保System.gc()后,SoftReference引用的referent被回收需要加入下面的参数
* -XX:SoftRefLRUPolicyMSPerMB=0
*/
public class ReferenceTest {
private static List roots = new ArrayList<>();
public static void main(String[] args) throws Exception {
ReferenceQueue rq = new ReferenceQueue();
new Thread(new Runnable() {
@Override
public void run() {
int i=0;
while (true) {
try {
Reference r = rq.remove();
System.out.println(“reference:”+r);
//为null说明referent被回收
System.out.println( “get:”+r.get());
i++;
System.out.println( “queue remove num:”+i);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
for(int i=0;i<100000;i++) {
byte[] a = new byte[1024*1024];
// 分别验证SoftReference,WeakReference,PhantomReference
Reference r = new SoftReference(a, rq);
//Reference r = new WeakReference(a, rq);
//Reference r = new PhantomReference(a, rq);
roots.add(r);
System.gc();
System.out.println(“produce”+i);
TimeUnit.MILLISECONDS.sleep(100);
}
}
}
通过jstack命令可以看到对应的Reference Handler thread
“Reference Handler” #2 daemon prio=10 os_prio=31 tid=0x00007f8fb2836800 nid=0x2e03 in Object.wait() [0x000070000082b000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
– waiting on <0x0000000740008878> (a java.lang.ref.Reference$Lock)
at java.lang.Object.wait(Object.java:502)
at java.lang.ref.Reference.tryHandlePending(Reference.java:191)
– locked <0x0000000740008878> (a java.lang.ref.Reference$Lock)
at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:153)
计算的规则是: free_heap 表示当前堆剩余的内存,单位是MB interval 表示最近一次GC’s clock 和 当前我们要判断的softReference的timestamp 差值 ms_per_mb is a constant number of milliseconds to keep around a SoftReference for each free megabyte in the heap(可以通过-XX:SoftRefLRUPolicyMSPerMB来设定) 那么判断依据就是: interval <= freeheap * ms_per_mb,如果为true,则保留,false则进行对象清除。 SoftReferences will always be kept for at least one GC after their last access。 因为 只要调用一次,那么clock和timestamp的值就会一样,clock-timestamp则为0,一定小于等于free_heap * ms_per_mb。 OpenJDK的大概referencePolicy.cpp代码是:
void LRUMaxHeapPolicy::setup() {
size_t max_heap = MaxHeapSize;
max_heap -= Universe::get_heap_used_at_last_gc();
max_heap /= M;
_max_interval = max_heap * SoftRefLRUPolicyMSPerMB;
assert(_max_interval >= 0,”Sanity check”);
}
bool LRUMaxHeapPolicy::should_clear_reference(oop p,
jlong timestamp_clock) {
jlong interval = timestamp_clock – java_lang_ref_SoftReference::timestamp(p);
assert(interval >= 0, “Sanity check”);
// The interval will be zero if the ref was accessed since the last scavenge/gc.
if(interval <= _max_interval) {
return false;
}
return true;
}
put num: 0 but caches size:1
put num: 1 but caches size:2
[GC (Allocation Failure) 23142K->20936K(125952K), 0.0199681 secs]
put num: 2 but caches size:1
put num: 3 but caches size:2
put num: 4 but caches size:3
[GC (Allocation Failure) 52293K->51672K(159232K), 0.0157178 secs]
put num: 5 but caches size:1
put num: 6 but caches size:2
put num: 7 but caches size:3
put num: 8 but caches size:4
put num: 9 but caches size:5
put num: 10 but caches size:6
[GC (Allocation Failure) 115728K->113064K(191488K), 0.0295324 secs]
[Full GC (Ergonomics) 113064K->61788K(237568K), 0.0172315 secs]
put num: 11 but caches size:1
put num: 12 but caches size:2
put num: 13 but caches size:3
put num: 14 but caches size:4
put num: 15 but caches size:5
put num: 16 but caches size:6
[GC (Allocation Failure) 124511K->123356K(291840K), 0.0174441 secs]
[Full GC (Ergonomics) 123356K->61788K(315392K), 0.0133423 secs]
put num: 17 but caches size:1
put num: 18 but caches size:2
put num: 19 but caches size:3
WeakHashMap实现原理很简单,它除了实现标准的Map接口,里面的机制也和HashMap的实现类似。从它entry子类中可以看出,它的key是用WeakReference包裹住的。当这个key对象本身不再被使用时,伴随着GC的发生,会自动把该key对应的entry都在Map中清除掉。它为啥能够自动清除呢?这就是利用上面我们讲的ReferenceQueue VS Reference的原理。WeakHashMap里声明了一个queue,Entry继承WeakReference,构造函数中用key和queue关联构造一个weakReference,当key不再被使用gc后会自动把把key注册到queue中:
/**
* Reference queue for cleared WeakEntries
*/
private final ReferenceQueue queue = new ReferenceQueue<>();
/**
* The entries in this hash table extend WeakReference, using its main ref
* field as the key.
*/
private static class Entry extends WeakReference implements Map.Entry {
V value;
final int hash;
Entry next;
/**
* Creates new entry.
*/
Entry(Object key, V value,
ReferenceQueue queue,
int hash, Entry next) {
super(key, queue);
this.value = value;
this.hash = hash;
this.next = next;
}
//代码省落
}
}
WeakHashMap关键的清理entry代码:
/**
* Expunges stale entries from the table.
*/
private void expungeStaleEntries() {
for (Object x; (x = queue.poll()) != null; ) {
synchronized (queue) {
@SuppressWarnings(“unchecked”)
Entry e = (Entry) x;
int i = indexFor(e.hash, table.length);
Entry prev = table[i];
Entry p = prev;
while (p != null) {
Entry next = p.next;
if (p == e) {
if (prev == e)
table[i] = next;
else
prev.next = next;
// Must not null out e.next;
// stale entries may be in use by a HashIterator
e.value = null; // Help GC
size–;
break;
}
prev = p;
p = next;
}
}
}
}
public void run() {
if (running)
return;
// Finalizer thread starts before System.initializeSystemClass
// is called. Wait until JavaLangAccess is available
while (!VM.isBooted()) {
// delay until VM completes initialization
try {
VM.awaitBooted();
} catch (InterruptedException x) {
// ignore and continue
}
}
final JavaLangAccess jla = SharedSecrets.getJavaLangAccess();
running = true;
for (;;) {
try {
Finalizer f = (Finalizer)queue.remove();
f.runFinalizer(jla);
} catch (InterruptedException x) {
// ignore and continue
}
}
}
//关键字的使用探讨/*访问关键词private 只能在本类中访问public 只能在本工程中访问protected 只能在包中和子类中访问默认的 只能在包中访问*//*final 类 方法 变量 final 类 不能被继承 final 方法 不能被子类覆盖,但可以继承 final 变量 只能有一次赋值,赋值后不能改变 final 不能用来修饰构造方法*///this()
What’s new in Zabbix 2.0?
去年开始使用Zabbix的时候,是1.8.X的版本,今年Zabbix已经跨入了2.0的时代。看了2.0的release notes,和performance相关的有下面几个:
:: Performance improvements::Trigger related da
修改jboss端口
%JBOSS_HOME%\server\{服务实例名}\conf\bindingservice.beans\META-INF\bindings-jboss-beans.xml
中找到
<!-- The ports-default bindings are obtained by taking the base bindin
@echo off
::演示:删除指定路径下指定天数之前(以文件名中包含的日期字符串为准)的文件。
::如果演示结果无误,把del前面的echo去掉,即可实现真正删除。
::本例假设文件名中包含的日期字符串(比如:bak-2009-12-25.log)
rem 指定待删除文件的存放路径
set SrcDir=C:/Test/BatHome
rem 指定天数
set DaysAgo=1
HTML5的video和audio标签是用来在网页中加入视频和音频的标签,在支持html5的浏览器中不需要预先加载Adobe Flash浏览器插件就能轻松快速的播放视频和音频文件。而html5media.js可以在不支持html5的浏览器上使video和audio标签生效。 How to enable <video> and <audio> tags in