Detailed explanation of common methods of ByteBuffer

Detailed explanation of common methods of ByteBuffer (transfer)

Buffer is to reserve a specified size of storage space in memory for temporary storage of input/output (I/O) data. This part of the reserved memory space is called buffer:

There are two benefits to using buffers:

1. Reduce the actual number of physical reads and writes

2. The buffer is allocated memory when it is created, and this memory area is always reused, which can reduce the number of dynamic allocation and recovery of memory

To give a simple example, for example, there are 1w bricks in site A that need to be moved to site B

Since there is no tool (buffer), we can only move one copy at a time, so we have to move 1w times (the actual number of reads and writes)

If A and B are far apart (IO performance consumption), then the performance consumption will be very large

But if we have a big truck (buffer) at this time that can transport 5000 copies at a time, then 2 times will be enough

Compared to before, the performance is definitely greatly improved.

So, buffer is very important in IO. BufferedInputStream, BufferedOutputStream, BufferedReader, and BufferedWriter in the old I/O library (relative to the java.nio package) use buffers in their implementations. The java.nio package exposes the Buffer API, which enables Java programs to directly control and manipulate buffers.

In Java NIO, the role of the buffer is also used to temporarily store data, which can be understood as a transfer station for data in I/O operations. The buffer directly serves the channel (Channel), writing data to the channel or reading data from the channel. Such operations can use the buffer data to transfer the data to achieve the purpose of efficient data processing. There are mainly eight buffer classes in NIO (MappedByteBuffer is a ByteBuffer dedicated to memory mapping):

Buffer

All buffers have 4 attributes: capacity, limit, position, mark, and follow: mark <= position <= limit <= capacity, the following table is an explanation of the 4 attributes:

Property description
Capacity Capacity, which is the maximum amount of data that can hold; is set when the buffer is created and cannot be changed
Limit Indicates the current end point of the buffer. Read and write operations cannot be performed on the position where the buffer exceeds the limit. and the limit can be modified
Position Position, the index of the next element to be read or written, the value will be changed every time the buffer data is read or written, ready for the next read and write
Mark Mark, call mark() to set mark=position, and then call reset() to restore the position to the marked position

Method:

1. Instantiate

The java.nio.Buffer class is an abstract class and cannot be instantiated. Direct subclasses of the Buffer class, such as ByteBuffer, are also abstract classes, so they cannot be instantiated.

But the ByteBuffer class provides 4 static factory methods to get an instance of ByteBuffer:

Method description
allocate(int capacity) Allocate a byte array of capacity size from the heap space as the byte data memory of the buffer
allocateDirect(int capacity) Instead of using the JVM stack, the operating system creates a memory block for use as a buffer, which is better coupled with the current operating system, thus further improving the speed of I/O operations. But the system overhead of allocating direct buffers is high, so only use such buffers when the buffers are large and long-lived, or need to be reused frequently
wrap(byte[] array) The data in this buffer will be stored in the byte array, and changes to the data in either the bytes array or the buff buffer will affect the other. In fact, the bottom layer of ByteBuffer originally has a bytes array responsible for saving the data in the buffer buffer. Through the allocate method, the system will help you construct a byte array
wrap(byte[] array, 
 int offset, int length)
在上一个方法的基础上可以指定偏移量和长度,这个offset也就是包装后byteBuffer的position,而length呢就是limit-position的大小,从而我们可以得到limit的位置为length+position(offset)

我写了这几个方法的测试方法,大家可以运行起来更容易理解

public static void main(String args[]) throws FileNotFoundException {

		System.out.println("----------Test allocate--------");
		System.out.println("before alocate:"
				+ Runtime.getRuntime().freeMemory());
		
		// 如果分配的内存过小,调用Runtime.getRuntime().freeMemory()大小不会变化?
		// 要超过多少内存大小JVM才能感觉到?
		ByteBuffer buffer = ByteBuffer.allocate(102400);
		System.out.println("buffer = " + buffer);
		
		System.out.println("after alocate:"
				+ Runtime.getRuntime().freeMemory());
		
		// 这部分直接用的系统内存,所以对JVM的内存没有影响
		ByteBuffer directBuffer = ByteBuffer.allocateDirect(102400);
		System.out.println("directBuffer = " + directBuffer);
		System.out.println("after direct alocate:"
				+ Runtime.getRuntime().freeMemory());
		
		System.out.println("----------Test wrap--------");
		byte[] bytes = new byte[32];
		buffer = ByteBuffer.wrap(bytes);
		System.out.println(buffer);
		
		buffer = ByteBuffer.wrap(bytes, 10, 10);
		System.out.println(buffer);	
	}
 

2. Other methods

Method description
limit (), limit (10) 等 The names of the methods for reading and setting these 4 attributes are similar to val() and val(10) in jQuery, one for get and one for set
reset() Set position to the value of mark, which is equivalent to making a mark before, and now you need to return to the place marked before
clear() position = 0;limit = capacity;mark = -1; a bit like initialization, but does not affect the content of the underlying byte array
flip() limit = position; position = 0; mark = -1; Flip, that is, let the area from position to limit after flip become the previous 0 to position, flip is to change a buffer in the state of storing data into A state that is ready to fetch data
rewind() Set position to 0, mark to -1, do not change the value of limit
remaining() return limit - position; returns the relative position difference between limit and position
hasRemaining() return position < limit Returns whether there is any unread content
compact() 把从position到limit中的内容移到0到limit-position的区域内,position和limit的取值也分别变成limit-position、capacity。如果先将positon设置到limit,再compact,那么相当于clear()
get() 相对读,从position位置读取一个byte,并将position+1,为下次读写作准备
get(int index) 绝对读,读取byteBuffer底层的bytes中下标为index的byte,不改变position
get(byte[] dst, int offset, int length) 从position位置开始相对读,读length个byte,并写入dst下标从offset到offset+length的区域
put(byte b) 相对写,向position的位置写入一个byte,并将postion+1,为下次读写作准备
put(int index, byte b) 绝对写,向 byteBuffer底层的bytes中下标为index的位置插入byte b,不改变position
put(ByteBuffer src) 用相对写,把src中可读的部分(也就是position到limit)写入此byteBuffer
put(byte[] src, int offset, int length) 从src数组中的offset到offset+length区域读取数据并使用相对写写入此byteBuffer

以下为一些测试方法:

public static void main(String args[]) throws FileNotFoundException {

		System.out.println("--------Test reset----------");
		buffer.clear();
		buffer.position(5);
		buffer.mark();
		buffer.position(10);
		System.out.println("before reset:" + buffer);
		buffer.reset();
		System.out.println("after reset:" + buffer);

		System.out.println("--------Test rewind--------");
		buffer.clear();
		buffer.position(10);
		buffer.limit(15);
		System.out.println("before rewind:" + buffer);
		buffer.rewind();
		System.out.println("before rewind:" + buffer);

		System.out.println("--------Test compact--------");
		buffer.clear();
		buffer.put("abcd".getBytes());
		System.out.println("before compact:" + buffer);
		System.out.println(new String(buffer.array()));
		buffer.flip();
		System.out.println("after flip:" + buffer);
		System.out.println((char) buffer.get());
		System.out.println((char) buffer.get());
		System.out.println((char) buffer.get());
		System.out.println("after three gets:" + buffer);
		System.out.println("\t" + new String(buffer.array()));
		buffer.compact();
		System.out.println("after compact:" + buffer);
		System.out.println("\t" + new String(buffer.array()));

		System.out.println("------Test get-------------");
		buffer = ByteBuffer.allocate(32);
		buffer.put((byte) 'a').put((byte) 'b').put((byte) 'c').put((byte) 'd')
				.put((byte) 'e').put((byte) 'f');
		System.out.println("before flip()" + buffer);
		// 转换为读取模式
		buffer.flip();
		System.out.println("before get():" + buffer);
		System.out.println((char) buffer.get());
		System.out.println("after get():" + buffer);
		// get(index)不影响position的值
		System.out.println((char) buffer.get(2));
		System.out.println("after get(index):" + buffer);
		byte[] dst = new byte[10];
		buffer.get(dst, 0, 2);
		System.out.println("after get(dst, 0, 2):" + buffer);
		System.out.println("\t dst:" + new String(dst));
		System.out.println("buffer now is:" + buffer);
		System.out.println("\t" + new String(buffer.array()));

		System.out.println("--------Test put-------");
		ByteBuffer bb = ByteBuffer.allocate(32);
		System.out.println("before put(byte):" + bb);
		System.out.println("after put(byte):" + bb.put((byte) 'z'));
		System.out.println("\t" + bb.put(2, (byte) 'c'));
		// put(2,(byte) 'c')不改变position的位置
		System.out.println("after put(2,(byte) 'c'):" + bb);
		System.out.println("\t" + new String(bb.array()));
		// 这里的buffer是 abcdef[pos=3 lim=6 cap=32]
		bb.put(buffer);
		System.out.println("after put(buffer):" + bb);
		System.out.println("\t" + new String(bb.array()));
	}
 

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326222685&siteId=291194637