Java Buffer緩沖區(qū)操作與內(nèi)存管理最佳實(shí)踐
Buffer緩沖區(qū)操作與內(nèi)存管理
1 Buffer的設(shè)計(jì)原理和內(nèi)存模型
1.1 Buffer到底是什么
Buffer就是Java NIO里的數(shù)據(jù)容器,專門用來存放各種基本類型的數(shù)據(jù)。你可以把它想象成一個(gè)智能的數(shù)組,不僅能存數(shù)據(jù),還知道自己當(dāng)前讀到哪了、寫到哪了。
和Channel配合使用時(shí),Buffer就像是數(shù)據(jù)的中轉(zhuǎn)站。Channel負(fù)責(zé)傳輸,Buffer負(fù)責(zé)存儲(chǔ),兩者分工明確。
Buffer有幾個(gè)設(shè)計(jì)特點(diǎn):
- 專一性:每種數(shù)據(jù)類型都有對(duì)應(yīng)的Buffer,比如ByteBuffer、IntBuffer
- 內(nèi)存靈活:可以用堆內(nèi)存,也可以用堆外內(nèi)存
- 狀態(tài)清晰:讀模式和寫模式分得很清楚
- 自動(dòng)跟蹤:會(huì)自動(dòng)記錄當(dāng)前操作的位置
1.2 Buffer家族成員
Java NIO的Buffer家族結(jié)構(gòu)很簡(jiǎn)單,就是一個(gè)抽象父類加上各種具體實(shí)現(xiàn):
Buffer (抽象類) ├── ByteBuffer // 最常用的,處理字節(jié)數(shù)據(jù) │ └── MappedByteBuffer // 內(nèi)存映射文件專用 │ ├── DirectByteBuffer // 直接內(nèi)存實(shí)現(xiàn) │ └── FileChannelImpl.MappedByteBufferAdapter ├── CharBuffer // 處理字符 ├── DoubleBuffer // 處理雙精度浮點(diǎn)數(shù) ├── FloatBuffer // 處理單精度浮點(diǎn)數(shù) ├── IntBuffer // 處理整數(shù) ├── LongBuffer // 處理長(zhǎng)整數(shù) └── ShortBuffer // 處理短整數(shù)
ByteBuffer是老大,用得最多,因?yàn)榫W(wǎng)絡(luò)傳輸和文件操作基本都是字節(jié)流。MappedByteBuffer是個(gè)特殊的存在,專門用來做內(nèi)存映射文件,讀寫大文件時(shí)特別有用。
1.3 Buffer的內(nèi)存模型
Buffer的內(nèi)存可以從兩個(gè)角度來看:
1.3.1 邏輯上怎么理解
邏輯上,Buffer就是一個(gè)有序的數(shù)組,里面裝著同一種類型的數(shù)據(jù)。每個(gè)位置都有索引,你可以直接跳到任意位置讀寫數(shù)據(jù)。
Buffer用三個(gè)重要的指針來管理這個(gè)數(shù)組:position(當(dāng)前位置)、limit(邊界)和capacity(總?cè)萘浚?。這三個(gè)指針決定了你能在哪讀、在哪寫、總共有多大空間。
1.3.2 物理上怎么實(shí)現(xiàn)
物理實(shí)現(xiàn)上,Buffer有兩種存儲(chǔ)方式:
堆緩沖區(qū)(HeapBuffer):
- 數(shù)據(jù)存在JVM堆內(nèi)存里
- 底層就是個(gè)普通的Java數(shù)組
- 會(huì)被垃圾回收器管理
- 創(chuàng)建方式:
ByteBuffer.allocate(1024)
直接緩沖區(qū)(DirectBuffer):
- 數(shù)據(jù)存在操作系統(tǒng)的原生內(nèi)存里(堆外內(nèi)存)
- 不占用JVM堆空間
- 垃圾回收器管不著,需要手動(dòng)或等待回收
- 創(chuàng)建方式:
ByteBuffer.allocateDirect(1024)
還有個(gè)特殊的MappedByteBuffer,它把文件直接映射到內(nèi)存里,讀寫文件就像操作內(nèi)存一樣快。
2 position、limit、capacity三大屬性詳解
Buffer有三個(gè)關(guān)鍵屬性:position、limit和capacity。這三個(gè)屬性就像是Buffer的GPS,告訴你現(xiàn)在在哪、能到哪、總共有多大。
2.1 capacity(容量)
capacity就是Buffer的總?cè)萘浚瑒?chuàng)建時(shí)就定死了,后面改不了。就像買了個(gè)1024字節(jié)的水桶,不管你裝多少水,桶的容量就是1024。
- 含義:Buffer最多能裝多少個(gè)元素
- 特點(diǎn):一旦創(chuàng)建就固定了
- 范圍:capacity ≥ 0
// 創(chuàng)建一個(gè)能裝1024個(gè)字節(jié)的Buffer ByteBuffer buffer = ByteBuffer.allocate(1024); int capacity = buffer.capacity(); // 返回1024,永遠(yuǎn)不變
2.2 position(位置)
position是個(gè)移動(dòng)的指針,指向下一個(gè)要操作的位置。每次讀寫數(shù)據(jù),這個(gè)指針就會(huì)自動(dòng)往前移。
- 含義:下一個(gè)要讀或?qū)懙奈恢?/li>
- 特點(diǎn):會(huì)隨著操作自動(dòng)移動(dòng)
- 范圍:0 ≤ position ≤ limit
寫模式時(shí),position指向下一個(gè)要寫入的地方;讀模式時(shí),position指向下一個(gè)要讀取的地方。
ByteBuffer buffer = ByteBuffer.allocate(10); buffer.put((byte) 'A'); // position從0跳到1 buffer.put((byte) 'B'); // position從1跳到2 int currentPosition = buffer.position(); // 現(xiàn)在是2
2.3 limit(限制)
limit是個(gè)邊界線,告訴你最多能操作到哪里。超過這條線就不能讀寫了。
- 含義:第一個(gè)不能碰的位置
- 特點(diǎn):可以手動(dòng)調(diào)整
- 范圍:position ≤ limit ≤ capacity
寫模式時(shí),limit就是capacity(能寫滿整個(gè)Buffer);讀模式時(shí),limit是之前寫了多少數(shù)據(jù)。
ByteBuffer buffer = ByteBuffer.allocate(10); // 寫模式:limit = capacity = 10,可以寫滿 int limitInWriteMode = buffer.limit(); // 返回10 // 寫入3個(gè)字節(jié)后切換到讀模式 buffer.put((byte) 'A').put((byte) 'B').put((byte) 'C'); buffer.flip(); // 切換到讀模式 // 讀模式:limit = 3,只能讀這3個(gè)字節(jié) int limitInReadMode = buffer.limit(); // 返回3
2.4 三個(gè)屬性的關(guān)系圖解
用一個(gè)例子來看看這三個(gè)屬性是怎么配合工作的:
// 創(chuàng)建一個(gè)能裝8個(gè)字節(jié)的Buffer
ByteBuffer buffer = ByteBuffer.allocate(8);
System.out.println("剛創(chuàng)建時(shí):");
System.out.println("capacity: " + buffer.capacity()); // 8,總?cè)萘?
System.out.println("limit: " + buffer.limit()); // 8,能寫到哪
System.out.println("position: " + buffer.position()); // 0,當(dāng)前位置
// 寫入數(shù)據(jù)
buffer.put("ABCD".getBytes());
System.out.println("\n寫入ABCD后:");
System.out.println("capacity: " + buffer.capacity()); // 8,總?cè)萘坎蛔?
System.out.println("limit: " + buffer.limit()); // 8,還能繼續(xù)寫
System.out.println("position: " + buffer.position()); // 4,指針移到第4位
// 切換到讀模式
buffer.flip();
System.out.println("\nflip()切換讀模式后:");
System.out.println("capacity: " + buffer.capacity()); // 8,總?cè)萘坎蛔?
System.out.println("limit: " + buffer.limit()); // 4,只能讀4個(gè)字節(jié)
System.out.println("position: " + buffer.position()); // 0,從頭開始讀狀態(tài)變化圖示:
剛創(chuàng)建(寫模式):
[0][1][2][3][4][5][6][7]
^ ^
position limit/capacity
寫入ABCD后:
[A][B][C][D][ ][ ][ ][ ]
^ ^
position limit/capacity
flip()后(讀模式):
[A][B][C][D][ ][ ][ ][ ]
^ ^ ^
position limit capacity2.5 mark(標(biāo)記)
mark就像是在Buffer上做個(gè)書簽,記住某個(gè)位置,以后可以快速跳回來。
- 含義:臨時(shí)記住的位置
- 特點(diǎn):可有可無,默認(rèn)沒有
- 范圍:mark ≤ position
ByteBuffer buffer = ByteBuffer.allocate(10); buffer.put((byte) 'A'); buffer.put((byte) 'B'); buffer.mark(); // 在position=2的地方做個(gè)書簽 buffer.put((byte) 'C'); buffer.reset(); // 跳回書簽位置(position=2)
3 讀寫模式切換和常用操作方法
3.1 讀寫模式切換
Buffer就像一個(gè)雙向通道,可以往里寫數(shù)據(jù),也可以從里面讀數(shù)據(jù)。但不能同時(shí)進(jìn)行,需要在寫模式和讀模式之間切換。
3.1.1 flip():寫模式切換到讀模式
public final Buffer flip() {
limit = position; // 設(shè)置讀取邊界
position = 0; // 從頭開始讀
mark = -1; // 清除書簽
return this;
}flip()就像翻書一樣,做三件事:
- 把當(dāng)前寫到的位置設(shè)為讀取邊界(limit = position)
- 把讀取指針拉回到開頭(position = 0)
- 清除之前的書簽(mark = -1)
這樣就能從頭開始讀取剛才寫入的數(shù)據(jù)了。
3.1.2 clear():讀模式切換到寫模式
public final Buffer clear() {
position = 0; // 從頭開始寫
limit = capacity; // 可以寫滿整個(gè)Buffer
mark = -1; // 清除書簽
return this;
}clear()就像清空黑板重新寫字,做三件事:
- 把寫入指針拉回到開頭(position = 0)
- 允許寫滿整個(gè)Buffer(limit = capacity)
- 清除之前的書簽(mark = -1)
注意:clear()并不會(huì)真的清除數(shù)據(jù),只是重置了指針,舊數(shù)據(jù)會(huì)被新數(shù)據(jù)覆蓋。
3.1.3 compact():部分讀模式切換到寫模式
public ByteBuffer compact() {
// 把沒讀完的數(shù)據(jù)移到前面
System.arraycopy(hb, ix(position()), hb, ix(0), remaining());
position(remaining()); // position指向未讀數(shù)據(jù)后面
limit(capacity()); // 可以寫滿整個(gè)Buffer
discardMark(); // 清除書簽
return this;
}compact()比較聰明,它會(huì)保留沒讀完的數(shù)據(jù):
- 把沒讀完的數(shù)據(jù)移到Buffer開頭
- position指向這些數(shù)據(jù)的后面(可以繼續(xù)寫新數(shù)據(jù))
- limit設(shè)為capacity(允許寫滿)
- 清除書簽
這樣既保留了未讀數(shù)據(jù),又能繼續(xù)寫入新數(shù)據(jù)。
3.2 常用操作方法
3.2.1 分配Buffer
// 在JVM堆內(nèi)存里創(chuàng)建,速度快 ByteBuffer heapBuffer = ByteBuffer.allocate(1024); // 在系統(tǒng)內(nèi)存里創(chuàng)建,I/O效率高 ByteBuffer directBuffer = ByteBuffer.allocateDirect(1024); // 把現(xiàn)有數(shù)組包裝成Buffer byte[] array = new byte[1024]; ByteBuffer wrappedBuffer = ByteBuffer.wrap(array);
3.2.2 寫入數(shù)據(jù)
// 寫一個(gè)字節(jié),position自動(dòng)+1 buffer.put((byte) 127); // 寫一串字節(jié) byte[] data = "Hello".getBytes(); buffer.put(data); // 在指定位置寫入,不影響position buffer.put(3, (byte) 65); // 在第3個(gè)位置寫入'A' // 從數(shù)組的某個(gè)位置開始,寫入指定長(zhǎng)度 buffer.put(data, 1, 3); // 從data[1]開始寫3個(gè)字節(jié)
3.2.3 讀取數(shù)據(jù)
// 讀一個(gè)字節(jié),position自動(dòng)+1 byte b = buffer.get(); // 讀一串字節(jié)到數(shù)組里 byte[] data = new byte[10]; buffer.get(data); // 從指定位置讀取,不影響position byte b = buffer.get(3); // 讀取第3個(gè)位置的字節(jié) // 讀指定長(zhǎng)度到數(shù)組的某個(gè)位置 buffer.get(data, 1, 3); // 讀3個(gè)字節(jié)到data[1]開始的位置
3.2.4 其他常用操作
// 做書簽和跳回書簽 buffer.mark(); // 在當(dāng)前position做個(gè)書簽 buffer.reset(); // 跳回書簽位置 // 倒帶,position回到0 buffer.rewind(); // 檢查還能讀多少 boolean hasRemaining = buffer.hasRemaining(); // 還有數(shù)據(jù)嗎? int remaining = buffer.remaining(); // 還剩多少個(gè)(limit - position) // 手動(dòng)移動(dòng)position buffer.position(buffer.position() + 3); // 跳過3個(gè)位置 // 復(fù)制Buffer,共享數(shù)據(jù)但各自有獨(dú)立的指針 ByteBuffer duplicate = buffer.duplicate(); // 創(chuàng)建只讀版本,不能修改數(shù)據(jù) ByteBuffer readOnlyBuffer = buffer.asReadOnlyBuffer(); // 切片,共享一部分?jǐn)?shù)據(jù) ByteBuffer slicedBuffer = buffer.slice(2, 5); // 從位置2開始,長(zhǎng)度5的片段
3.3 Buffer操作的最佳實(shí)踐
- 檢查返回值:讀寫操作可能沒有處理完所有數(shù)據(jù)
- 記得flip():寫完數(shù)據(jù)要調(diào)用flip()才能讀取
- 重復(fù)利用:用clear()或compact()重用Buffer,別老是new
- 選對(duì)類型:什么數(shù)據(jù)用什么Buffer(ByteBuffer、IntBuffer等)
- 直接緩沖區(qū)要小心:它不歸垃圾回收器管,用完要手動(dòng)釋放
4 直接緩沖區(qū)vs非直接緩沖區(qū)的性能差異
4.1 兩種緩沖區(qū)的實(shí)現(xiàn)機(jī)制
4.1.1 非直接緩沖區(qū)(HeapBuffer)
非直接緩沖區(qū)就是在JVM堆內(nèi)存里創(chuàng)建的Buffer,底層用的是普通Java數(shù)組。做I/O操作時(shí),JVM需要把數(shù)據(jù)在堆內(nèi)存和系統(tǒng)內(nèi)存之間復(fù)制一遍。
ByteBuffer heapBuffer = ByteBuffer.allocate(1024); // 在堆內(nèi)存里創(chuàng)建
內(nèi)部實(shí)現(xiàn):
// HeapByteBuffer的底層實(shí)現(xiàn)(簡(jiǎn)化版)
final byte[] hb; // 就是個(gè)普通數(shù)組
final int offset; // 數(shù)組里的起始位置
// 讀取操作
public byte get() {
return hb[ix(nextGetIndex())];
}
// 寫入操作
public ByteBuffer put(byte b) {
hb[ix(nextPutIndex())] = b;
return this;
}4.1.2 直接緩沖區(qū)(DirectBuffer)
直接緩沖區(qū)是在系統(tǒng)內(nèi)存里創(chuàng)建的Buffer,不在JVM堆里。它通過JNI調(diào)用系統(tǒng)API分配內(nèi)存,Java通過Unsafe類來訪問這塊內(nèi)存。
ByteBuffer directBuffer = ByteBuffer.allocateDirect(1024); // 在系統(tǒng)內(nèi)存里創(chuàng)建
內(nèi)部實(shí)現(xiàn):
// DirectByteBuffer的底層實(shí)現(xiàn)(簡(jiǎn)化版)
private long address; // 系統(tǒng)內(nèi)存地址
// 讀取操作
public byte get() {
return Unsafe.getByte(ix(nextGetIndex())); // 直接從系統(tǒng)內(nèi)存讀
}
// 寫入操作
public ByteBuffer put(byte b) {
Unsafe.putByte(ix(nextPutIndex()), b); // 直接寫到系統(tǒng)內(nèi)存
return this;
}4.2 性能差異分析
4.2.1 內(nèi)存分配性能
| 緩沖區(qū)類型 | 分配速度 | 釋放速度 | 內(nèi)存壓力 |
|---|---|---|---|
| 非直接緩沖區(qū) | 快 | GC自動(dòng)回收 | 占用堆內(nèi)存 |
| 直接緩沖區(qū) | 慢(要調(diào)系統(tǒng)API) | 看GC臉色或手動(dòng)釋放 | 不占堆內(nèi)存 |
直接緩沖區(qū)創(chuàng)建比較慢,因?yàn)橐{(diào)用系統(tǒng)API分配內(nèi)存。但一旦創(chuàng)建好了,做I/O操作時(shí)通常比非直接緩沖區(qū)快。
4.2.2 I/O操作性能
| 緩沖區(qū)類型 | 讀寫性能 | 數(shù)據(jù)復(fù)制 | 適用場(chǎng)景 |
|---|---|---|---|
| 非直接緩沖區(qū) | 一般 | 要在堆內(nèi)存和系統(tǒng)內(nèi)存間復(fù)制 | 小數(shù)據(jù)、偶爾用用 |
| 直接緩沖區(qū) | 快 | 不用復(fù)制 | 大數(shù)據(jù)、頻繁I/O |
直接緩沖區(qū)做I/O時(shí)比較快,因?yàn)椴挥迷诙褍?nèi)存和系統(tǒng)內(nèi)存之間復(fù)制數(shù)據(jù)。用Channel傳輸數(shù)據(jù)時(shí),直接緩沖區(qū)可以直接參與,而非直接緩沖區(qū)還得先復(fù)制到一個(gè)臨時(shí)的直接緩沖區(qū)里。
4.2.3 內(nèi)存訪問性能
| 緩沖區(qū)類型 | 讀寫速度 | CPU緩存友好性 | JVM優(yōu)化 |
|---|---|---|---|
| 非直接緩沖區(qū) | 一般更快 | 好 | JIT能優(yōu)化 |
| 直接緩沖區(qū) | 通過JNI訪問,可能慢點(diǎn) | 一般 | 優(yōu)化有限 |
如果只是在Java代碼里頻繁讀寫B(tài)uffer,非直接緩沖區(qū)通常更快,因?yàn)樗贘VM堆里,JIT編譯器能優(yōu)化,對(duì)CPU緩存也更友好。
4.3 性能測(cè)試案例
來個(gè)實(shí)際測(cè)試,看看兩種Buffer在不同場(chǎng)景下的表現(xiàn):
public class BufferPerformanceTest {
private static final int BUFFER_SIZE = 1024 * 1024; // 1MB大小
private static final int ITERATIONS = 1000; // 測(cè)試1000次
public static void main(String[] args) throws Exception {
// 測(cè)試創(chuàng)建速度
testAllocation();
// 測(cè)試I/O速度
testIO();
// 測(cè)試讀寫速度
testMemoryAccess();
}
private static void testAllocation() {
long start, end;
// 測(cè)試堆內(nèi)存Buffer創(chuàng)建速度
start = System.nanoTime();
for (int i = 0; i < ITERATIONS; i++) {
ByteBuffer buffer = ByteBuffer.allocate(BUFFER_SIZE); // 在堆里創(chuàng)建
buffer.put((byte) 1); // 寫點(diǎn)數(shù)據(jù)
}
end = System.nanoTime();
System.out.println("堆Buffer創(chuàng)建: " + (end - start) / 1000000 + "ms");
// 測(cè)試直接Buffer創(chuàng)建速度
start = System.nanoTime();
for (int i = 0; i < ITERATIONS; i++) {
ByteBuffer buffer = ByteBuffer.allocateDirect(BUFFER_SIZE); // 在系統(tǒng)內(nèi)存創(chuàng)建
buffer.put((byte) 1); // 寫點(diǎn)數(shù)據(jù)
}
end = System.nanoTime();
System.out.println("直接Buffer創(chuàng)建: " + (end - start) / 1000000 + "ms");
}
private static void testIO() throws Exception {
File tempFile = File.createTempFile("buffer-test", ".tmp"); // 創(chuàng)建臨時(shí)文件
tempFile.deleteOnExit(); // 程序結(jié)束時(shí)刪除
// 準(zhǔn)備測(cè)試數(shù)據(jù)
ByteBuffer data = ByteBuffer.allocate(BUFFER_SIZE);
while (data.hasRemaining()) {
data.put((byte) 'A'); // 填充數(shù)據(jù)
}
data.flip(); // 切換到讀模式
// 測(cè)試堆Buffer的I/O速度
ByteBuffer heapBuffer = ByteBuffer.allocate(BUFFER_SIZE);
testFileIO(heapBuffer, tempFile, "堆Buffer I/O");
// 測(cè)試直接Buffer的I/O速度
ByteBuffer directBuffer = ByteBuffer.allocateDirect(BUFFER_SIZE);
testFileIO(directBuffer, tempFile, "直接Buffer I/O");
}
private static void testFileIO(ByteBuffer buffer, File file, String label) throws Exception {
FileChannel channel = new FileOutputStream(file).getChannel(); // 獲取文件通道
long start = System.nanoTime(); // 開始計(jì)時(shí)
for (int i = 0; i < ITERATIONS; i++) {
buffer.clear(); // 清空Buffer,準(zhǔn)備寫入
buffer.put(new byte[BUFFER_SIZE]); // 寫入數(shù)據(jù)
buffer.flip(); // 切換到讀模式
while (buffer.hasRemaining()) {
channel.write(buffer); // 寫到文件
}
}
channel.close(); // 關(guān)閉通道
long end = System.nanoTime(); // 結(jié)束計(jì)時(shí)
System.out.println(label + ": " + (end - start) / 1000000 + "ms");
}
private static void testMemoryAccess() {
ByteBuffer heapBuffer = ByteBuffer.allocate(BUFFER_SIZE); // 堆Buffer
ByteBuffer directBuffer = ByteBuffer.allocateDirect(BUFFER_SIZE); // 直接Buffer
// 測(cè)試堆Buffer讀寫速度
long start = System.nanoTime();
for (int i = 0; i < ITERATIONS; i++) {
for (int j = 0; j < 1024; j++) {
heapBuffer.put(j, (byte) j); // 在指定位置寫入
}
for (int j = 0; j < 1024; j++) {
byte b = heapBuffer.get(j); // 從指定位置讀取
}
}
long end = System.nanoTime();
System.out.println("堆Buffer讀寫: " + (end - start) / 1000000 + "ms");
// 測(cè)試直接Buffer讀寫速度
start = System.nanoTime();
for (int i = 0; i < ITERATIONS; i++) {
for (int j = 0; j < 1024; j++) {
directBuffer.put(j, (byte) j); // 在指定位置寫入
}
for (int j = 0; j < 1024; j++) {
byte b = directBuffer.get(j); // 從指定位置讀取
}
}
end = System.nanoTime();
System.out.println("直接Buffer讀寫: " + (end - start) / 1000000 + "ms");
}
}4.4 選擇合適的緩沖區(qū)類型
根據(jù)性能特點(diǎn),可以按照以下原則選擇Buffer類型:
| 場(chǎng)景 | 推薦Buffer類型 | 原因 |
|---|---|---|
| 大文件I/O | 直接Buffer | 不用復(fù)制內(nèi)存,I/O快 |
| 網(wǎng)絡(luò)通信 | 直接Buffer | 減少數(shù)據(jù)復(fù)制,吞吐量高 |
| 臨時(shí)小數(shù)據(jù)處理 | 堆Buffer | 創(chuàng)建快,GC友好 |
| 頻繁創(chuàng)建銷毀 | 堆Buffer | 避免直接Buffer創(chuàng)建的開銷 |
| 長(zhǎng)期重用的Buffer | 直接Buffer | 一次創(chuàng)建多次使用,攤銷成本 |
在物聯(lián)網(wǎng)平臺(tái)的實(shí)際應(yīng)用中,通常會(huì)根據(jù)不同場(chǎng)景選擇不同Buffer類型:
- 設(shè)備數(shù)據(jù)采集:用直接Buffer處理大量傳感器數(shù)據(jù)
- 配置信息傳輸:用堆Buffer處理小型配置數(shù)據(jù)
- 文件存儲(chǔ):用直接Buffer或MappedByteBuffer處理大型日志文件
- 實(shí)時(shí)數(shù)據(jù)處理:用直接Buffer提高網(wǎng)絡(luò)通信效率
5 總結(jié)
Buffer是Java NIO的核心組件,就像一個(gè)智能的數(shù)據(jù)容器,讓我們能高效地處理各種數(shù)據(jù)。通過掌握Buffer的工作原理、核心屬性和操作方法,以及兩種Buffer類型的性能特點(diǎn),我們就能在物聯(lián)網(wǎng)平臺(tái)等高性能應(yīng)用中做出更好的技術(shù)選擇。
Buffer的核心價(jià)值:
- 和Channel完美配合:讓I/O操作變得高效
- 靈活的內(nèi)存管理:既能用堆內(nèi)存,也能用系統(tǒng)內(nèi)存
- 精確的狀態(tài)控制:通過position、limit、capacity準(zhǔn)確控制數(shù)據(jù)讀寫
- 類型安全:針對(duì)不同數(shù)據(jù)類型提供專門的Buffer
掌握了Buffer,我們就為學(xué)習(xí)Java NIO打下了堅(jiān)實(shí)基礎(chǔ)。下一篇文章,我們將深入探討Selector選擇器,看看它如何實(shí)現(xiàn)多路復(fù)用I/O,讓一個(gè)線程同時(shí)處理多個(gè)連接。
到此這篇關(guān)于Java Buffer緩沖區(qū)操作與內(nèi)存管理的文章就介紹到這了,更多相關(guān)Java Buffer緩沖區(qū)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java基礎(chǔ)之位運(yùn)算知識(shí)總結(jié)
最近接觸到了java位運(yùn)算,之前對(duì)位運(yùn)算的了解僅僅停留在表現(xiàn)結(jié)果上,乘2除以2,對(duì)背后的原理并不了解,現(xiàn)在學(xué)習(xí)記錄一下,需要的朋友可以參考下2021-05-05
在SpringBoot里自定義Spring MVC配置的三種方法
SpringBoot幫我們自動(dòng)配好了 MVC 的核心組件,但實(shí)際開發(fā)中,光用默認(rèn)配置肯定不夠今天就教你 3 種自定義 Spring MVC 配置的方法,從簡(jiǎn)單到復(fù)雜,新手也能一步步跟著做,需要的朋友可以參考下2026-03-03
Java編程實(shí)現(xiàn)用hash方法切割文件
這篇文章主要介紹了Java編程實(shí)現(xiàn)用hash方法切割文件,簡(jiǎn)單介紹了hash的概念,然后分享了使用方法示例,具有一定借鑒價(jià)值,需要的朋友可以了解下。2017-12-12
springboot實(shí)現(xiàn)基于aop的切面日志
這篇文章主要為大家詳細(xì)介紹了springboot實(shí)現(xiàn)基于aop的切面日志,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-09-09
java double 溢出報(bào)錯(cuò)的問題解決
在進(jìn)行Java開發(fā)時(shí),經(jīng)常會(huì)遇到數(shù)字溢出的問題,這個(gè)問題在很多程序中都非常常見,尤其是在進(jìn)行數(shù)值計(jì)算的時(shí)候,本文就來介紹一下如何解決,感興趣的可以了解一下2025-09-09
Java日常練習(xí)題,每天進(jìn)步一點(diǎn)點(diǎn)(9)
下面小編就為大家?guī)硪黄狫ava基礎(chǔ)的幾道練習(xí)題(分享)。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧,希望可以幫到你2021-07-07
分享Java8中通過Stream對(duì)列表進(jìn)行去重的實(shí)現(xiàn)
本文主要介紹了分享Java8中通過Stream對(duì)列表進(jìn)行去重的實(shí)現(xiàn),包括兩種方法,具有一定的參考價(jià)值,感興趣的可以了解一下2023-11-11
SpringBoot實(shí)現(xiàn)Read Through模式的操作過程
Read Through模式通常是指一種緩存策略,其中當(dāng)應(yīng)用程序嘗試讀取數(shù)據(jù)時(shí),緩存系統(tǒng)首先被檢查以查看數(shù)據(jù)是否已經(jīng)存在于緩存中,這篇文章主要介紹了SpringBoot實(shí)現(xiàn)Read Through模式,需要的朋友可以參考下2024-07-07

