/** * Constructs a reader that decodes bytes from the given channel using the given decoder. */ publicstatic Reader newReader(ReadableByteChannel ch, CharsetDecoder dec, int minBufferCap){ checkNotNull(ch, "ch"); return StreamDecoder.forDecoder(ch, dec.reset(), minBufferCap);// new StreamDecoder(...); } publicstatic Reader newReader(ReadableByteChannel ch, String csName){ checkNotNull(csName, "csName"); return newReader(ch, Charset.forName(csName).newDecoder(), -1); }
Given a direct byte buffer, the Java virtual machine will make a best effort to perform native I/O operations directly upon it. That is, it will attempt to avoid copying the buffer’s content to (or from) an intermediate buffer before (or after) each invocation of one of the underlying operating system’s native I/O operations.
The contents of direct buffers may reside outside of the normal garbage-collected heap, and so their impact upon the memory footprint of an application might not be obvious.
It is therefore recommended that direct buffers be allocated primarily for large, long-lived buffers that are subject to the underlying system’s native I/O operations.
In general it is best to allocate direct buffers only when they yield a measureable gain in program performance.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
ByteBuffer(int mark, int pos, int lim, int cap, // package-private byte\[\] hb, int offset){ super(mark, pos, lim, cap); this.hb = hb; /// Non-null only for heap buffers this.offset = offset; /// } Buffer(int mark, int pos, int lim, int cap) { // package-private if (cap < 0) thrownewIllegalArgumentException("Negative capacity: " + cap); this.capacity = cap; limit(lim); position(pos); if (mark >= 0) { if (mark > pos) thrownewIllegalArgumentException("mark > position: (" + mark + " > " + pos + ")"); this.mark = mark; } }
Direct Buffers
1 2 3 4 5 6 7 8 9 10 11
// Allocates a new direct byte buffer. // this method typically have somewhat higher allocation and deallocation costs than non-direct buffers. 更高的分配和释放成本 public static ByteBuffer allocateDirect(int capacity) { return new DirectByteBuffer(capacity); }
// Maps a region of this channel's file directly into memory. //Read/write: Changes made to the resulting buffer will eventually be propagated to the file; they may or may not be made visible to other programs that have mapped the same file. //它们可能对映射了同一文件的其他程序可见,也可能不可见。 //Private: Changes made to the resulting buffer will not be propagated to the file and will not be visible to other programs that have mapped the same file; instead, they will cause private copies of the modified portions of the buffer to be created. public abstract MappedByteBuffer map(MapMode mode, long position, long size) throws IOException;
MappedByteBuffer
A direct byte buffer whose content is a memory-mapped region of a file. A mapped byte buffer and the file mapping that it represents remain valid until the buffer itself is garbage-collected.
For most operating systems, mapping a file into memory is more expensive than reading or writing a few tens of kilobytes of data via the usual {@link #read read} and {@link #write write} methods. From the standpoint of performance it is generally only worth mapping relatively large files into memory.
// Tells whether or not this buffer's content is resident in physical memory. // A return value of <tt>false</tt> does not necessarily imply that the buffer's content is not resident in physical memory. // The returned value is a hint, rather than a guarantee, // because the underlying operating system may // have paged out some of the buffer's data by the time that an invocation of this method returns. publicfinalbooleanisLoaded() { checkMapped(); if ((address == 0) || (capacity() == 0)) returntrue; longoffset= mappingOffset(); longlength= mappingLength(offset); return isLoaded0(mappingAddress(offset), length, Bits.pageCount(length)); } privatenativebooleanisLoaded0(long address, long length, int pageCount);
// Loads this buffer's content into physical memory. // This method makes a best effort to ensure that ... publicfinal MappedByteBuffer load() { checkMapped(); if ((address == 0) || (capacity() == 0)) returnthis; longoffset= mappingOffset(); longlength= mappingLength(offset); load0(mappingAddress(offset), length);
// A checksum is computed as we go along to prevent the compiler from otherwise // considering the loop as dead code. Unsafeunsafe= Unsafe.getUnsafe(); intps= Bits.pageSize(); intcount= Bits.pageCount(length); longa= mappingAddress(offset); bytex=0; for (int i=0; i<count; i++) { x ^= unsafe.getByte(a);//Read a byte from each page to bring it into memory. a += ps; } if (unused != 0) unused = x;
returnthis; } privatenativevoidload0(long address, long length);
// Forces any changes made to this buffer's content to be written to the storage device containing the mapped file. // If the file mapped into this buffer resides on a local storage device // then when this method returns it is guaranteed that // all changes made to the buffer since it was created, or since this method was last invoked, will have been written to that device. // // If the file does not reside on a local device then no such guarantee is made. publicfinal MappedByteBuffer force() {// read/write mode checkMapped(); if ((address != 0) && (capacity() != 0)) { longoffset= mappingOffset(); force0(fd, mappingAddress(offset), mappingLength(offset)); } returnthis; }