一段好玩的測(cè)試LinkedBlockingQueue.poll超時(shí)的程序
由于在出現(xiàn)這個(gè)現(xiàn)象的時(shí)候有看到過(guò)OutOfMemory的錯(cuò),雖然java進(jìn)程沒(méi)退出,但猜想可能是這個(gè)原因造成的,于是寫(xiě)了下面這段代碼:
long beginTime=System.currentTimeMillis();
Map<String, byte[]> cache=new HashMap<String, byte[]>();
for (int i = 0; i < 1000000; i++) {
cache.put(String.valueOf(i),new byte[500]);
}
CountDownLatch latch=new CountDownLatch(25);
for (int i = 0; i < 5; i++) {
for (int j = 0; j < 5; j++) {
Thread thread=new Thread(new TestThread(latch));
thread.start();
}
}
latch.await();
long endTime=System.currentTimeMillis();
System.out.println("總共執(zhí)行時(shí)間:"+(endTime-beginTime));
}
static class TestThread implements Runnable{
private CountDownLatch latch;
public TestThread(CountDownLatch latch){
this.latch=latch;
}
public void run(){
BlockingQueue<String> queue=new LinkedBlockingQueue<String>(1);
try{
for (int i = 0; i < 5; i++) {
long beginTime=System.currentTimeMillis();
queue.poll(100, TimeUnit.MILLISECONDS);
long endTime=System.currentTimeMillis();
long consumeTime=endTime-beginTime;
if(consumeTime>200)
System.out.println("獲取queue的時(shí)間為:"+consumeTime);
@SuppressWarnings("unused")
byte[] bytesNew=new byte[25506000];
}
}
catch(Exception e){
;
}
latch.countDown();
}
}
啟動(dòng)上面程序時(shí),將jvm參數(shù)設(shè)置為-Xms640M -Xmx640M,運(yùn)行后,應(yīng)該會(huì)看到有很多queue.poll執(zhí)行超過(guò)200ms的現(xiàn)象,甚至?xí)霈F(xiàn)8000ms的現(xiàn)象。
上面整段程序的寫(xiě)法就是用大量的小對(duì)象占據(jù)old generation,然后啟動(dòng)多個(gè)線程,每個(gè)線程運(yùn)行的時(shí)候new一個(gè)大的對(duì)象,讓其產(chǎn)生有可能直接從new generation分配到old generation,從而導(dǎo)致Full GC頻繁執(zhí)行,里面的byte數(shù)組的大小的原則為:塞滿(mǎn)內(nèi)存,產(chǎn)生Full GC,但又盡量不讓?xiě)?yīng)用出現(xiàn)OutOfMemory,或者說(shuō)不出現(xiàn)過(guò)于頻繁的OutOfMemory,避免jvm crash。
從上面程序的運(yùn)行效果來(lái)看,當(dāng)jvm內(nèi)存消耗的很?chē)?yán)重的情況下,poll的超時(shí)是沒(méi)法準(zhǔn)的,其實(shí)分析下原因,還是挺正常的:
1、jvm內(nèi)存消耗嚴(yán)重的情況下,Minor GC和Full GC瘋狂執(zhí)行,導(dǎo)致了應(yīng)用的執(zhí)行不斷的被暫停,因此當(dāng)線程已經(jīng)進(jìn)入poll等待后,這個(gè)線程沒(méi)有機(jī)會(huì)被執(zhí)行,導(dǎo)致當(dāng)其有機(jī)會(huì)執(zhí)行時(shí),早就超過(guò)了指定的超時(shí)時(shí)間,因此其超時(shí)不準(zhǔn)并不是本身的機(jī)制導(dǎo)致的,而是jvm GC造成的多次暫停;
2、多次暫停的情況下,jvm需要不斷的調(diào)度恢復(fù)線程,這需要消耗很多的資源,而且切換多了Swap空間很容易不夠用,最終導(dǎo)致jvm crash。
posted on 2009-03-12 16:52 BlueDavy 閱讀(7809) 評(píng)論(4) 編輯 收藏 所屬分類(lèi): Java