池化技术
原文作者:楊冠標(biāo)?
原文地址:常見池化技術(shù)
在系統(tǒng)開發(fā)過程中,我們經(jīng)常會用到池化技術(shù)來減少系統(tǒng)消耗,提升系統(tǒng)性能。
- 線程池通過復(fù)用線程提升性能。簡單來說,池化技術(shù)就是通過復(fù)用來提升性能。
- 對象池通過復(fù)用對象來減少創(chuàng)建對象、垃圾回收的開銷;
- 連接池(數(shù)據(jù)庫連接池、Redis連接池和HTTP連接池等)通過復(fù)用TCP連接來減少創(chuàng)建和釋放連接的時間。
線程、內(nèi)存、數(shù)據(jù)庫的連接對象都是資源,在程序中,當(dāng)你創(chuàng)建一個線程或者在堆上申請一塊內(nèi)存的時候都涉及到很多的系統(tǒng)調(diào)用,也是非常消耗CPU的。如果你的程序需要很多類似的工作線程或者需要頻繁地申請釋放小塊內(nèi)存,在沒有對這方面進行優(yōu)化的情況下,這部分代碼很可能會成為影響你整個程序性能的瓶頸。
線程池
線程池的原理很簡單,類似于操作系統(tǒng)中的緩沖區(qū)的概念。線程池中會先啟動若干數(shù)量的線程,這些線程都處于睡眠狀態(tài)。當(dāng)客戶端有一個新的請求時,就會喚醒線程池中的某一個睡眠的線程,讓它來處理客戶端的這個請求,當(dāng)處理完這個請求之后,線程又處于睡眠的狀態(tài)。
線程池能很高地提升程序的性能。比如有一個省級數(shù)據(jù)大集中的銀行網(wǎng)絡(luò)中心,高峰期每秒的客戶端請求并發(fā)數(shù)超過100,如果為每個客戶端請求創(chuàng)建一個新的線程的話,那耗費的CPU時間和內(nèi)存都是十分驚人的,如果采用一個擁有200個線程的線程池,那將會節(jié)約大量的系統(tǒng)資源,使得更多的CPU時間和內(nèi)存用來處理實際的商業(yè)應(yīng)用,而不是頻繁的線程創(chuàng)建和銷毀。
內(nèi)存池
如何更好地管理應(yīng)用程序內(nèi)存的使用,同時提高內(nèi)存使用的頻率,這時值得每一個開發(fā)人員深思的問題。內(nèi)存池(Memory Pool)就提供了一個比較可行的解決方案。
內(nèi)存池在創(chuàng)建的過程中,會預(yù)先分配足夠大的內(nèi)存,形成一個初步的內(nèi)存池。然后每次用戶請求內(nèi)存的時候,就會返回內(nèi)存池中的一塊空閑的內(nèi)存,并將這塊內(nèi)存的標(biāo)志置為已使用。當(dāng)內(nèi)存使用完畢釋放內(nèi)存的時候,也不是真正地調(diào)用free或delete的過程,而是把內(nèi)存放回內(nèi)存池的過程,且放回的過程要把標(biāo)志置為空閑。最后,應(yīng)用程序結(jié)束,就會將內(nèi)存池銷毀,將內(nèi)存池中的每一塊內(nèi)存釋放。
使用內(nèi)存池的優(yōu)點:
- 減少內(nèi)存碎片的產(chǎn)生。這個優(yōu)點可以從創(chuàng)建內(nèi)存池的過程中看出,當(dāng)我們在創(chuàng)建內(nèi)存池的時候,分配的都是一塊塊比較規(guī)整的內(nèi)存塊,減少內(nèi)存碎片的產(chǎn)生。
- 提高了內(nèi)存的使用頻率。這個可以從分配內(nèi)存和釋放內(nèi)存的過程中看出。每次的分配和釋放并不是去調(diào)用系統(tǒng)提供的函數(shù)或操作符去操作實際的內(nèi)存,而是在復(fù)用內(nèi)存池中的內(nèi)存。
使用內(nèi)存池的缺點:
- 缺點就是很可能會造成內(nèi)存的浪費,因為要使用內(nèi)存池需要在一開始分配一大塊閑置的內(nèi)存,而這些內(nèi)存不一定全部被用到。
數(shù)據(jù)庫連接池
數(shù)據(jù)庫連接池的基本思想是在系統(tǒng)初始化的時候?qū)?shù)據(jù)庫連接作為對象存儲在內(nèi)存中,當(dāng)用戶需要訪問數(shù)據(jù)庫的時候,并非建立一個新的連接,而是從連接池中取出一個已建立的空閑連接對象。在使用完畢后,用戶也不是將連接關(guān)閉,而是將連接放回到連接池中,以供下一個請求訪問使用。這些連接的建立、斷開都由連接池自身來管理。
同時,還可以設(shè)置連接池的參數(shù)來控制連接池中的初始連接數(shù)、連接的上下限數(shù)和每個連接的最大使用次數(shù)、最大空閑時間等。當(dāng)然,也可以通過連接池自身的管理機制來監(jiān)視連接的數(shù)量、使用情況等。
HttpClient連接池
HttpClient我們經(jīng)常用來進行HTTP服務(wù)訪問。我們的項目中會有一個獲取任務(wù)執(zhí)行狀態(tài)的功能使用HttpClient,一秒鐘請求一次,經(jīng)常會出現(xiàn)Conection Reset異常。經(jīng)過分析發(fā)現(xiàn),問題是出在HttpClient的每次請求都會新建一個連接,當(dāng)創(chuàng)建連接的頻率比關(guān)閉連接的頻率大的時候,就會導(dǎo)致系統(tǒng)中產(chǎn)生大量處于TIME_CLOSED狀態(tài)的連接。這個時候使用連接池復(fù)用連接就能解決這個問題。
總結(jié)
不難看出,這些池化技術(shù)的實現(xiàn)原理都是類似的,都是通過對連接或線程的復(fù)用,并對復(fù)用的數(shù)量、時間等進行控制,從而使系統(tǒng)的性能和資源消耗達到最優(yōu)的狀態(tài)。
實際項目中,我們可以考慮使用池化技術(shù)來解決程序性能上的瓶頸。
總結(jié)
- 上一篇: Java并发编程—为什么 wait()
- 下一篇: Java并发—线程池ThreadPool