背景
最近在研究netty的源代码,发现netty的内存管理都是用jdk的ByteBuffer。为了更深入的了解bytebuffer,因此有了这篇文章
ByteBuffer的基本组成
ByteBuffer 的基本函数http://kakajw.iteye.com/blog/1797073
ByteBuffer分为两类DirectBuffer和HeapBuffer。DirectBuffer速度快于HeapBuffer。DirectBuffer可以直接将数据输出到终端,避免内存拷贝。DirectBuffer的分配开销大于HeapBuffer。但是DirectBuffer不用GC。因此DirectBuffer一般用于大块,且长期使用的内存。因此特别适用于Netty的内存分配模型。详细的说明如下:
* <p> A byte buffer is either <i>direct</i> or <i>non-direct</i>. 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. * * <p> A direct byte buffer may be created by invoking the {@link * #allocateDirect(int) allocateDirect} factory method of this class. The * buffers returned by this method typically have somewhat higher allocation * and deallocation costs than non-direct buffers. 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. * * <p> A direct byte buffer may also be created by {@link * java.nio.channels.FileChannel#map </code>mapping<code>} a region of a file * directly into memory. An implementation of the Java platform may optionally * support the creation of direct byte buffers from native code via JNI. If an * instance of one of these kinds of buffers refers to an inaccessible region * of memory then an attempt to access that region will not change the buffer's * content and will cause an unspecified exception to be thrown either at the * time of the access or at some later time. * * <p> Whether a byte buffer is direct or non-direct may be determined by * invoking its {@link #isDirect isDirect} method. This method is provided so * that explicit buffer management can be done in performance-critical code.
ByteBuffer继承于Buffer对象,Buffer的成员变量和方法如下:
public abstract class Buffer { // Invariants: mark <= position <= limit <= capacity private int mark = -1; //标记的位置 private int position = 0; //当前位置 private int limit; //限制大小 private int capacity; //总的内存容量 // Used only by direct buffers // NOTE: hoisted here for speed in JNI GetDirectBufferAddress long address; /** * Sets this buffer's mark at its position. </p> * * @return This buffer */ public final Buffer mark() { mark = position; return this; } /** * Resets this buffer's position to the previously-marked position. * * <p> Invoking this method neither changes nor discards the mark's * value. </p> * * @return This buffer * * @throws InvalidMarkException * If the mark has not been set */ public final Buffer reset() { int m = mark; if (m < 0) throw new InvalidMarkException(); position = m; return this; } /** * Clears this buffer. The position is set to zero, the limit is set to * the capacity, and the mark is discarded. * * <p> Invoke this method before using a sequence of channel-read or * <i>put</i> operations to fill this buffer. For example: * * <blockquote><pre> * buf.clear(); // Prepare buffer for reading * in.read(buf); // Read data</pre></blockquote> * * <p> This method does not actually erase the data in the buffer, but it * is named as if it did because it will most often be used in situations * in which that might as well be the case. </p> * * @return This buffer */ public final Buffer clear() { position = 0; limit = capacity; mark = -1; return this; } /** * Flips this buffer. The limit is set to the current position and then * the position is set to zero. If the mark is defined then it is * discarded. * * <p> After a sequence of channel-read or <i>put</i> operations, invoke * this method to prepare for a sequence of channel-write or relative * <i>get</i> operations. For example: * * <blockquote><pre> * buf.put(magic); // Prepend header * in.read(buf); // Read data into rest of buffer * buf.flip(); // Flip buffer * out.write(buf); // Write header + data to channel</pre></blockquote> * * <p> This method is often used in conjunction with the {@link * java.nio.ByteBuffer#compact compact} method when transferring data from * one place to another. </p> * * @return This buffer */ public final Buffer flip() { limit = position; position = 0; mark = -1; return this; } /** * Rewinds this buffer. The position is set to zero and the mark is * discarded. * * <p> Invoke this method before a sequence of channel-write or <i>get</i> * operations, assuming that the limit has already been set * appropriately. For example: * * <blockquote><pre> * out.write(buf); // Write remaining data * buf.rewind(); // Rewind buffer * buf.get(array); // Copy data into array</pre></blockquote> * * @return This buffer */ public final Buffer rewind() { position = 0; mark = -1; return this; } }
ByteBuffer的主要接口
public abstract class ByteBuffer extends Buffer implements Comparable<ByteBuffer> { // These fields are declared here rather than in Heap-X-Buffer in order to // reduce the number of virtual method invocations needed to access these // values, which is especially costly when coding small buffers. // final byte[] hb; // Non-null only for heap buffers final int offset; boolean isReadOnly; // Valid only for heap buffers /** * Creates a new byte buffer whose content is a shared subsequence of * this buffer's content. * * <p> The content of the new buffer will start at this buffer's current * position. Changes to this buffer's content will be visible in the new * buffer, and vice versa; the two buffers' position, limit, and mark * values will be independent. * * <p> The new buffer's position will be zero, its capacity and its limit * will be the number of bytes remaining in this buffer, and its mark * will be undefined. The new buffer will be direct if, and only if, this * buffer is direct, and it will be read-only if, and only if, this buffer * is read-only. </p> * * @return The new byte buffer */ public abstract ByteBuffer slice(); /** * Creates a new byte buffer that shares this buffer's content. * * <p> The content of the new buffer will be that of this buffer. Changes * to this buffer's content will be visible in the new buffer, and vice * versa; the two buffers' position, limit, and mark values will be * independent. * * <p> The new buffer's capacity, limit, position, and mark values will be * identical to those of this buffer. The new buffer will be direct if, * and only if, this buffer is direct, and it will be read-only if, and * only if, this buffer is read-only. </p> * * @return The new byte buffer */ public abstract ByteBuffer duplicate(); /** * Creates a new, read-only byte buffer that shares this buffer's * content. * * <p> The content of the new buffer will be that of this buffer. Changes * to this buffer's content will be visible in the new buffer; the new * buffer itself, however, will be read-only and will not allow the shared * content to be modified. The two buffers' position, limit, and mark * values will be independent. * * <p> The new buffer's capacity, limit, position, and mark values will be * identical to those of this buffer. * * <p> If this buffer is itself read-only then this method behaves in * exactly the same way as the {@link #duplicate duplicate} method. </p> * * @return The new, read-only byte buffer */ public abstract ByteBuffer asReadOnlyBuffer(); }
MappedByteBuffer 实现了ByteBuffer接口,内存映射到文件
/** * A direct byte buffer whose content is a memory-mapped region of a file. * * <p> Mapped byte buffers are created via the {@link * java.nio.channels.FileChannel#map FileChannel.map} method. This class * extends the {@link ByteBuffer} class with operations that are specific to * memory-mapped file regions. * * <p> A mapped byte buffer and the file mapping that it represents remain * valid until the buffer itself is garbage-collected. * * <p> The content of a mapped byte buffer can change at any time, for example * if the content of the corresponding region of the mapped file is changed by * this program or another. Whether or not such changes occur, and when they * occur, is operating-system dependent and therefore unspecified. * * <a name="inaccess"><p> All or part of a mapped byte buffer may become * inaccessible at any time, for example if the mapped file is truncated. An * attempt to access an inaccessible region of a mapped byte buffer will not * change the buffer's content and will cause an unspecified exception to be * thrown either at the time of the access or at some later time. It is * therefore strongly recommended that appropriate precautions be taken to * avoid the manipulation of a mapped file by this program, or by a * concurrently running program, except to read or write the file's content. * * <p> Mapped byte buffers otherwise behave no differently than ordinary direct * byte buffers. </p> * * * @author Mark Reinhold * @author JSR-51 Expert Group * @since 1.4 */ public abstract class MappedByteBuffer extends ByteBuffer { // This is a little bit backwards: By rights MappedByteBuffer should be a // subclass of DirectByteBuffer, but to keep the spec clear and simple, and // for optimization purposes, it's easier to do it the other way around. // This works because DirectByteBuffer is a package-private class. // For mapped buffers, a FileDescriptor that may be used for mapping // operations if valid; null if the buffer is not mapped. private final FileDescriptor fd; /** * Tells whether or not this buffer's content is resident in physical * memory. * * <p> A return value of <tt>true</tt> implies that it is highly likely * that all of the data in this buffer is resident in physical memory and * may therefore be accessed without incurring any virtual-memory page * faults or I/O operations. A return value of <tt>false</tt> does not * necessarily imply that the buffer's content is not resident in physical * memory. * * <p> 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. </p> * * @return <tt>true</tt> if it is likely that this buffer's content * is resident in physical memory */ public final boolean isLoaded() { checkMapped(); if ((address == 0) || (capacity() == 0)) return true; long offset = mappingOffset(); long length = mappingLength(offset); return isLoaded0(mappingAddress(offset), length, Bits.pageCount(length)); } // not used, but a potential target for a store, see load() for details. private static byte unused; /** * Loads this buffer's content into physical memory. * * <p> This method makes a best effort to ensure that, when it returns, * this buffer's content is resident in physical memory. Invoking this * method may cause some number of page faults and I/O operations to * occur. </p> * * @return This buffer */ public final MappedByteBuffer load() { checkMapped(); if ((address == 0) || (capacity() == 0)) return this; long offset = mappingOffset(); long length = mappingLength(offset); load0(mappingAddress(offset), length); // Read a byte from each page to bring it into memory. A checksum // is computed as we go along to prevent the compiler from otherwise // considering the loop as dead code. Unsafe unsafe = Unsafe.getUnsafe(); int ps = Bits.pageSize(); int count = Bits.pageCount(length); long a = mappingAddress(offset); byte x = 0; for (int i=0; i<count; i++) { x ^= unsafe.getByte(a); a += ps; } if (unused != 0) unused = x; return this; } /** * Forces any changes made to this buffer's content to be written to the * storage device containing the mapped file. * * <p> 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. * * <p> If the file does not reside on a local device then no such guarantee * is made. * * <p> If this buffer was not mapped in read/write mode ({@link * java.nio.channels.FileChannel.MapMode#READ_WRITE}) then invoking this * method has no effect. </p> * * @return This buffer */ public final MappedByteBuffer force() { checkMapped(); if ((address != 0) && (capacity() != 0)) { long offset = mappingOffset(); force0(fd, mappingAddress(offset), mappingLength(offset)); } return this; } }
DirectByteBuffer继承MappedByteBuffer
class DirectByteBuffer extends MappedByteBuffer implements DirectBuffer { // Cached unsafe-access object protected static final Unsafe unsafe = Bits.unsafe(); // Cached array base offset private static final long arrayBaseOffset = (long)unsafe.arrayBaseOffset(byte[].class); // Cached unaligned-access capability protected static final boolean unaligned = Bits.unaligned(); // Base address, used in all indexing calculations // NOTE: moved up to Buffer.java for speed in JNI GetDirectBufferAddress // protected long address; // An object attached to this buffer. If this buffer is a view of another // buffer then we use this field to keep a reference to that buffer to // ensure that its memory isn't freed before we are done with it. private final Object att; DirectByteBuffer(int cap) { // package-private super(-1, 0, cap, cap); boolean pa = VM.isDirectMemoryPageAligned(); int ps = Bits.pageSize(); long size = Math.max(1L, (long)cap + (pa ? ps : 0)); Bits.reserveMemory(size, cap); long base = 0; try { //分配内存空间 base = unsafe.allocateMemory(size); } catch (OutOfMemoryError x) { Bits.unreserveMemory(size, cap); throw x; } //设置内存为0 unsafe.setMemory(base, size, (byte) 0); if (pa && (base % ps != 0)) { // Round up to page boundary address = base + ps - (base & (ps - 1)); } else { address = base; } //设置内存回收器 cleaner = Cleaner.create(this, new Deallocator(base, size, cap)); att = null; } //用剩下的空间创建一个直接缓存 public ByteBuffer slice() { int pos = this.position(); int lim = this.limit(); assert (pos <= lim); int rem = (pos <= lim ? lim - pos : 0); int off = (pos << 0); assert (off >= 0); return new DirectByteBuffer(this, -1, 0, rem, rem, off); } //拷贝一个直接缓存 public ByteBuffer duplicate() { return new DirectByteBuffer(this, this.markValue(), this.position(), this.limit(), this.capacity(), 0); } private short getShort(long a) { if (unaligned) { //不对齐的系统,不能通过一次获取多个字节 short x = unsafe.getShort(a); return (nativeByteOrder ? x : Bits.swap(x)); } return Bits.getShort(a, bigEndian); } public short getShort() { return getShort(ix(nextGetIndex((1 << 1)))); } private ByteBuffer putShort(long a, short x) { if (unaligned) { short y = (x); unsafe.putShort(a, (nativeByteOrder ? y : Bits.swap(y))); } else { Bits.putShort(a, x, bigEndian); } return this; } public ByteBuffer putShort(short x) { putShort(ix(nextPutIndex((1 << 1))), x); return this; } }
HeapByteBuffer是堆缓存,通过new byte[cap]方法分配。
class HeapByteBuffer extends ByteBuffer { // For speed these fields are actually declared in X-Buffer; // these declarations are here as documentation /* protected final byte[] hb; protected final int offset; */ HeapByteBuffer(int cap, int lim) { // package-private super(-1, 0, lim, cap, new byte[cap], 0); /* hb = new byte[cap]; offset = 0; */ } public short getShort() { return Bits.getShort(this, ix(nextGetIndex(2)), bigEndian); } public short getShort(int i) { return Bits.getShort(this, ix(checkIndex(i, 2)), bigEndian); } public ByteBuffer putShort(short x) { Bits.putShort(this, ix(nextPutIndex(2)), x, bigEndian); return this; } public ByteBuffer putShort(int i, short x) { Bits.putShort(this, ix(checkIndex(i, 2)), x, bigEndian); return this; } }
相关推荐
ByteBuffer的用法是Java NIO学习中的核心内容。 首先,我们了解下ByteBuffer的基本概念。ByteBuffer是一个字节缓冲区,可以存储字节序列。在NIO中,所有的数据读写都通过缓冲区进行,ByteBuffer与其他类型的Buffer...
在Java编程语言中,`ByteBuffer`是Java NIO(New IO)框架中的核心类之一,它提供了一种高效处理字节数据的方式。...通过深入学习和实践,我们可以利用Java NIO提供的强大功能,编写出更加灵活和高效的代码。
易语言汇编版ByteBuffer...总之,易语言汇编版ByteBuffer源码是一个结合了易语言和汇编语言优势的实用工具,对于进行网络编程的开发者来说,它提供了高效的数据处理手段,同时也为学习者提供了深入理解底层机制的机会。
1. **ServerBootstrap**配置:学习如何设置服务器启动参数,如绑定端口、配置EventLoopGroup等。 2. **ChannelHandler**编写:实现自定义处理器,处理进来的数据和事件。 3. **Pipeline构建**:了解如何定制处理链,...
通过阅读和理解这些代码,我们可以深入学习如何在Java中运用字节流和字符流进行文件操作,以及如何在需要时进行两者之间的转换。 总的来说,字节流和字符流是Java I/O系统的重要组成部分,理解它们的工作原理和应用...
本资料集合对Apache Mina进行了深入探讨,涵盖了Mina的关键组件和概念,包括IoFilter、IoHandler、ByteBuffer以及线程模型等。 1. **IoFilter与IoHandler**: IoFilter是Mina中的过滤器机制,它允许在数据传输过程...
了解以上知识点是掌握Apache MINA的基础,通过提供的学习资料,如《Mina2.0学习笔记》、《Apache MINA入门基础》和《Apache MINA Server 2.0中文参考手册》等,可以深入学习MINA的API用法、设计原理和最佳实践。...
接着,我们深入学习Netty的异步模型。Netty采用非阻塞I/O,通过EventLoopGroup管理多个线程,每个线程负责处理多个连接,从而实现高效的并发处理。这种模型大大减少了线程切换的开销,提高了系统性能。 Netty的协议...
对于想要深入学习Netty的开发者来说,理解并掌握以下知识点至关重要: 1. Netty的EventLoop和EventLoopGroup:了解线程模型和任务调度机制。 2. Channel和ChannelHandlerContext:理解数据传输的载体和上下文信息。...
通过深入学习 Netty,开发者可以构建出高效、稳定的高并发服务器,实现复杂网络应用的需求。《深入浅出Netty.pdf》这本书很可能会详细讲解这些知识点,包括理论基础、实践示例以及高级特性的使用,对于理解和掌握 ...
总的来说,《Netty 权威指南2》的源码部分会涉及网络编程基础、并发模型、内存管理、协议处理等多个方面的知识,是一份深入学习和研究Netty不可多得的资料。通过深入学习,开发者不仅能掌握Netty的使用,还能具备...
通过对这些文件的分析和理解,开发者可以深入学习到如何设计和实现一个完整的数据管理系统,包括客户端和服务器端的交互机制、数据库操作、以及如何使用Java和相关框架来构建高效稳定的应用。此外,对于有兴趣进一步...
本书《Java NIO Programming Cookbook》旨在深入浅出地介绍如何利用Java NIO进行高效的I/O编程,并提供了源码供读者实践和学习。 在Java NIO中,`ByteBuffer`是核心类之一,它用于存储和读写数据。`...
Java中的异步套接字编程,也称为非阻塞I/O...在提供的`src`压缩包文件中,可能包含了实现上述AIO示例的源代码,通过阅读和理解这些代码,开发者可以深入学习Java AIO的工作原理和用法,从而提升在网络编程领域的技能。
### Java NIO 学习 #### 一、Java NIO 的背景及意义 在Java早期版本(JDK 1.4之前),IO操作主要依赖于`java.io`包中的流式(stream-based)API,这类API是阻塞式的。虽然对于大多数日常应用场景而言,这种模型...
在深入学习 Netty 之前,首先理解其基本概念至关重要。Netty 是基于 Java NIO(非阻塞I/O)构建的,它的设计目标是提供一个高效、灵活且易于使用的网络通信框架。NIO 允许一个线程处理多个连接,避免了传统阻塞 I/O ...
本篇文章将深入探讨如何使用Java NIO(非阻塞I/O)来实现阻塞多线程通信,这对于高性能服务器端应用尤其重要。我们将会分析`EchoServer.java`、`EchoClient.java`和`SocketUtils.java`这三个文件中的关键知识点。 ...
在Android开发中,硬编码(Hard Coding)通常指的是将数据、配置或逻辑直接写入代码,而不是通过外部文件或资源来动态获取。...对于想要深入学习Android多媒体处理和编码的开发者来说,这是一个宝贵的资源。
在Java编程领域,NIO(New Input/Output)是一个重要的概念,它为处理大量输入输出提供了更为高效的方式,相比传统的IO模型,NIO具有非阻塞、多路复用...通过深入学习和实践,开发者可以更好地应对高并发场景下的挑战。
在Java开发领域,Netty作为一个...开发者应深入学习其设计理念和操作方式,以便在实际项目中更好地利用Netty提供的强大功能。通过掌握ByteBuf,不仅可以优化内存使用,还能提高代码的可读性和维护性,降低系统复杂性。