RocketMQ 中出現 org.apache.rocketmq.store.logfile.DefaultMappedFile#warmMappedFile
作用的交出cpu控制權, 在unix中 使用是時間片算法,而在windows中是搶佔式。
在時間片算法中,所有進程使用隊列排隊。操作系統會按他們的順序進行分配時間進行執行。該進程在該時間內執行,如果超過時間還沒執行完成,將會被剝奪cpu使用權並分配給另外一個進程。如果在該時間內結束或者阻塞。則cpu切換給其他進行。
搶戰式就是一個進行得到cpu使用權,除非他主動放棄。不然就會一直霸佔這個cpu。 Thead.sleep(0),就是當前線程放棄cpu使用。觸發操作系統爭奪cpu的爭奪。如果更高級別的優先權的進程或者線程要使用,則cpu交給他們使用,沒有的話還會返回到當前進程。
而這裏因爲是for的int ,沒有安全點,所以要等到循環結束後纔會觸發 觸發安全點檢查 (比如觸發GC回收) ,而上面圖片中進行讓每1000進行觸發 安全點檢查, 而不是每次都進行。
所以如果for 裏面的int循環太多,進行會發生內存溢出的情況,因爲沒有及時GC。
通過上圖的int循環就可以看出來,sleep(1000) 之後,主線程執行結果是等int 循環結束才進行返回 結果的,for循環中沒有進行 安全點檢查,等結束才進行,也可以for結束了才進行GC 。這都是因爲int是可數循環( 後續有介紹) 。
而上圖中進行了sleep(0) ,因爲吧cpu從當前線程中交出,所以進行了安全點檢查,進行GC回收。
通過上圖的long循環就可以看出來,sleep(1000) 之後,主線程馬上執行結果,而不是等待long循環結束。
下面講解下 safepoint ,也就是安全點
關於安全點的描述,我們可以看看《深入理解JVM虛擬機(第三版)》的 3.4.2 小節:
可數循環和不可數循環
是HotSpot虛擬機爲了避免安全點過多帶來過重的負擔,對循環還有一項優化措施,認爲循環次數較少的話,執行時間應該也不會太長,所以使用int類型或範圍更小的數據類型作爲索引值的循環默認是不會被放置安全點的。這種循環被稱爲可數循環(Counted Loop),相對應地,使用long或者範圍更大的數據類型作爲索引值的循環就被稱爲不可數循環(Uncounted Loop),將會被放置安全點。
意思就是在可數循環(Counted Loop)的情況下,HotSpot 虛擬機搞了一個優化,就是等循環結束之後,線程纔會進入安全點。
反過來說就是:循環如果沒有結束,線程不會進入安全點,GC 線程就得等着當前的線程循環結束,進入安全點,才能開始工作。
另外調用native 返回的時候也會觸發安全檢查,因爲native不屬於jvm裏面。所以從native回來的時候會觸發
建議仔細看完“why技術” 寫的文章《沒有二十年功力,寫不出sleep(0)這一行“看似無用”的代碼》
引用:
面試官:Thread.sleep(0) 有什麼用
沒有二十年功力,寫不出sleep(0)這一行
JVM系列之:再談java中的safepoint