1萤厅、文件IO
使用 Off Heap 堆外內(nèi)存,減少了堆內(nèi)向堆外拷貝過程蜜笤,效率要高一些濒蒋,
堆內(nèi):JVM 堆內(nèi)內(nèi)存。
堆外:JVM堆外把兔,JAVA 進程堆內(nèi)沪伙。
mapped
映射:是 mmap
調(diào)用的一個進程和內(nèi)核共享的內(nèi)存區(qū)域,且這個內(nèi)存區(qū)域是 PageCache 到文件的映射县好。
性能表現(xiàn) mapped > off heap > on heep
围橡。
Java 普通IO,每次調(diào)用寫操作聘惦,都會向 OS PageCache 溢寫某饰,而 Buffered IO(8KB)儒恋,向其寫入時,僅寫入到 JVM 內(nèi)存黔漂,知道寫滿之后诫尽,才會溢寫到 PageCache。
對比來看炬守,Buffered 少了很多 system call
和 int 0x80
牧嫉,因此效率高很多。
ByteBuffer
內(nèi)存分配
- 堆內(nèi)分配:
ByteBuffer.allocate(1024)
- 堆外分配:
ByteBuffer.allocateDirect(1024)
函數(shù)
-
put
:寫入數(shù)據(jù)减途,并移動 position 指針酣藻。
-
flip
:由寫模式切換到讀模式。讀模式下調(diào)用鳍置,會使 limit 指向當(dāng)前 position 位置辽剧,造成指針錯亂。
-
get
:讀取數(shù)據(jù)税产,并移動 position 指針怕轿。讀操作應(yīng)在 flip 操作后執(zhí)行,否則可能讀取到錯誤數(shù)據(jù)辟拷。
-
compact
:壓縮數(shù)據(jù)撞羽,并切換到寫模式。如果在寫模式調(diào)用衫冻,數(shù)據(jù)會錯亂诀紊,因為 limit 指向 了 tail。
-
mark
-reset
:標(biāo)記 position 位置隅俘,重置 position 到 mark 位置邻奠,不會切換讀寫模式,讀寫模式都可用为居。
-
slice
:創(chuàng)建一個新的字節(jié)緩沖區(qū)惕澎,其內(nèi)容是給定緩沖區(qū)內(nèi)容的共享子序列。新緩沖區(qū)的內(nèi)容將從該緩沖區(qū)的當(dāng)前位置開始颜骤。對該緩沖區(qū)內(nèi)容的更改將在新緩沖區(qū)中可見,反之亦然捣卤。這兩個緩沖區(qū)的位置忍抽,限制和標(biāo)記值將是獨立的。
新緩沖區(qū)的位置將為零董朝,其容量和限制將為該緩沖區(qū)中剩余的浮點數(shù)鸠项,并且其標(biāo)記將不確定。當(dāng)且僅當(dāng)該緩沖區(qū)是直接緩沖區(qū)時子姜,新緩沖區(qū)才是直接緩沖區(qū)祟绊;當(dāng)且僅當(dāng)該緩沖區(qū)是只讀緩沖區(qū)時,新緩沖區(qū)才是只讀緩沖區(qū)。
rewind
:清除 mark 標(biāo)記牧抽,并將 position 指針 重置為0嘉熊。clear
:重置緩沖區(qū),清除 mark 標(biāo)記扬舒,重置 position 指針阐肤,重置 limit 指針,回歸寫模式讲坎。
RandomAccessFile
Mode | 說明 |
---|---|
r | 打開文件僅僅是為了讀取數(shù)據(jù)孕惜,如果嘗試調(diào)用任何寫入數(shù)據(jù)的操作都會造成返回IOException錯誤信息的問題。 |
rw | 打開文件用于讀寫兩種操作晨炕,如果文件本身并不存在衫画,則會創(chuàng)建一個全新的文件。 |
rwd | 打開文件用于讀寫兩種操作瓮栗,這點和 rw 的操作完全一致削罩,但是只會在 cache 滿,或者調(diào)用 RandomAccessFile.close() 的時候才會執(zhí)行內(nèi)容同步操作遵馆。 |
rws | 在 rwd 的基礎(chǔ)上對內(nèi)容同步的要求更加嚴(yán)苛鲸郊,每write修改一個byte都會直接修改到磁盤中。 |
RandomAccessFile raf = new RandomAccessFile(new File("/path/to/file"), "rw");
// 寫數(shù)據(jù)
raf.write(new byte[5]);
// 移動指針
raf.seek(0L);
// 跳過字節(jié)
raf.skipBytes(1);
// 讀數(shù)據(jù) off:輸入數(shù)組偏移量 len:讀字節(jié)數(shù)
raf.read(new byte[10], 0, 10);
// 關(guān)閉并寫盤
raf.close();
FileChannel
RandomAccessFile raf = new RandomAccessFile(new File("/path/to/file"), "rw");
FileChannel channel = raf.getChannel();
// Zero Copy
channel.transferTo(position, count, target);
channel.transferFrom(src, position, count);
MappedByteBuffer
- 不通過系統(tǒng)調(diào)用货邓,數(shù)據(jù)直接到達(dá) PageCache秆撮。
-
mmap
的內(nèi)存映射,依然受內(nèi)核 pageCache 體系所約束换况。 - DirectIO 是忽略內(nèi)核的 PageCache职辨,Java 沒有直接使用內(nèi)核 DirectIO 的支持,需要C程序JNI擴展庫戈二。
- MappedByteBuffer 只是交給程序開辟自己的字節(jié)數(shù)組充當(dāng) PageCache舒裤,仍需要程序動用代碼維護一致性/Dirty等一系列問題。
MapMode | 說明 |
---|---|
FileChannel.MapMpde.READ_ONLY | Mode for a read-only mapping. 只讀模式觉吭。 |
FileChannel.MapMpde.READ_WRITE | Mode for a read/write mapping. 讀寫模式腾供。 |
FileChannel.MapMpde.PRIVATE | Mode for a private (copy-on-write) mapping. 堆內(nèi)存更改不會寫入文件。 |
RandomAccessFile raf = new RandomAccessFile(new File("/path/to/file"), "rw");
FileChannel channel = raf.getChannel();
MappedByteBuffer map = channel.map(FileChannel.MapMode.READ_WRITE, 0, 4090);
// 其余操作函數(shù)可參考 ByteBuffer
map.put(new byte[10]);
// PC數(shù)據(jù)寫入存儲設(shè)備
buffer.force();
2鲜滩、TCP網(wǎng)絡(luò)IO
服務(wù)端 LISTEN 狀態(tài)端口號伴鳖,最多65535個。
服務(wù)端無需為 Client 連接分配隨機端口號徙硅,只要四元組(源IP榜聂、源端口、目標(biāo)IP嗓蘑、目標(biāo)端口)不同须肆,就可以確定一個連接匿乃。
三次握手是內(nèi)核級的,ServerSocket
啟動之后豌汇,客戶端連接時幢炸,無需等待 server.accept()
即可完成三次握手,建立連接瘤礁。
因為客戶端連接是連接層業(yè)務(wù)阳懂,不需要等待應(yīng)用層響應(yīng)。
客戶端連接建立之后柜思,server.accept()
之前岩调,OS 僅僅開辟資源,并不會分配 FD赡盘。
當(dāng) server.accept()
之后号枕,OS 才會創(chuàng)建 FD,F(xiàn)D 在 Java 中體現(xiàn)為 Socket
對象陨享。
ServerSocket配置
BACK_LOG:未
accept
的連接隊列長度葱淳,超過此數(shù)量的連接,在netstat
中體現(xiàn)為SYN_RECV
狀態(tài)抛姑。SO_TIMEOUT:
server.accept()
超時配置赞厕,超過閾值未收到連接請求,會跑出SocketTimeoutException
異常定硝,但并不會造成server
崩潰皿桑。RECEIVE_BUFFER_SIZE:最大接收窗口,默認(rèn) 8192蔬啡。最終數(shù)值由三次握手之后雙方最小緩沖區(qū)為基準(zhǔn)诲侮。
-
REUSE_ADDRESS:端口重用。如果禁用箱蟆,在程序關(guān)閉后沟绪,端口可能會繼續(xù)占用一段時間,如果此時立刻重啟程序空猜,會拋出異常绽慈。
綁定到相同端口的程序,必須全部啟用該配置辈毯,才可重用端口久信,設(shè)置此參數(shù)必須在程序綁定到一個本地端口之前調(diào)用。
Socker配置
KEEP_ALIVE:TCP連接空閑時是否需要向?qū)Ψ桨l(fā)送探測包漓摩,依賴于底層的TCP模塊實現(xiàn)的,Java中只能設(shè)置是否開啟入客,不能設(shè)置其詳細(xì)參數(shù)管毙,依賴于系統(tǒng)配置腿椎。
SO_TIMEOUT:在與此
Socket
關(guān)聯(lián)的InputStream
上調(diào)用read()
將只阻塞此時間長度,超時將引發(fā)SocketTimeoutException
夭咬,但socket
不會崩潰啃炸。-
OOB_INLINE:TCP的緊急指針,一般不建議使用卓舵,且不同的TCP/IP實現(xiàn)不同南用。
雖然
Socket.sendUrgentData()
的參數(shù)是int
類型,但只有這個int類型的低字節(jié)被發(fā)送掏湾,其它的三個字節(jié)被忽略裹虫。客戶端和服務(wù)端必須同時開啟,否則無法使用
Socket.sendUrgentData()
發(fā)送數(shù)據(jù)融击。 RECEIVE_BUFFER_SIZE:最大接收窗口筑公,默認(rèn) 8192。最終數(shù)值由三次握手之后雙方最小緩沖區(qū)為基準(zhǔn)尊浪。
SEND_BUFFER_SIZE:最大發(fā)送窗口匣屡,默認(rèn) 8192。最終數(shù)值由三次握手之后雙方最小緩沖區(qū)為基準(zhǔn)拇涤。
-
REUSE_ADDRESS:端口重用捣作。如果禁用,在程序關(guān)閉后鹅士,端口可能會繼續(xù)占用一段時間券躁,如果此時立刻重啟程序,會拋出異常如绸。
綁定到相同端口的程序嘱朽,必須全部啟用該配置,才可重用端口怔接,設(shè)置此參數(shù)必須在程序綁定到一個本地端口之前調(diào)用搪泳。
-
SO_LINGER:控制 Socket 關(guān)閉行為,
- 默認(rèn)情況執(zhí)行
Socket.close()
立即返回扼脐,但底層的連接不會立即關(guān)閉岸军,會延遲一段時間,直到數(shù)據(jù)發(fā)送完成瓦侮,才會真正的關(guān)閉 Socket艰赞,斷開連接。 -
Socket.setSoLinger(true, 0)
:執(zhí)行Socket.close()
會立即返回肚吏,底層 Socket 立即關(guān)閉方妖,所有未發(fā)送數(shù)據(jù)被丟棄。 -
Socket.setSoLinger(true, 3600)
:執(zhí)行Socket.close()
會進入阻塞狀態(tài)罚攀,底層 Socket 嘗試發(fā)送剩余數(shù)據(jù)党觅,直到如下條件解除阻塞狀態(tài):- 剩余數(shù)據(jù)發(fā)送完成雌澄。
- 剩余數(shù)據(jù)未發(fā)送完成,但阻塞超過 3600毫秒杯瞻,立即返回镐牺,且丟棄剩余數(shù)據(jù)。
- 默認(rèn)情況執(zhí)行
TCP_NO_DELAY:默認(rèn)
false
魁莉,為啟用 Nagle算法睬涧。Nagle 算法的立意是,避免網(wǎng)絡(luò)中充塞小封包旗唁,提高網(wǎng)絡(luò)的利用率畦浓。