NIO && Netty PTT演示
一个EventLoopGroup(就一个带等待队列的线程池)包含一个或多个EventLoop,一个EventLoop生命周期里只跟一个Thread绑定。Reactor模型是boss(mainReactor)线程组和worker(subReactor)线程组隔离,boss和worker都是EventLoopGroup类型,boss负责监听建立连接组装channel并select事件,然后将有事件发生的channel交由Acceptor事件处理器(其实是boss线程组中的一个handler)分发给worker,work负责channel的读写,不要让worker线程组的拥挤影响到优先级高的boss线程组。Netty源码解析
1、netty TCP是每个客户端连接过来都有一条连接,而netty UDP没有连接,只监听端口。netty TCP可以在Channel获取远程客户端的ip和端口号,而UDP 无法从Channel获取远程客户端的ip和端口号,而是通过发过来的DatagramPacket中的sender获取发送消息客户端的ip和端口号。netty TCP消息通常需要粘包和拆包,netty UDP不需要粘包拆包,每个包都是完整的。
• FileChannel 的执行文件拷贝操作时用户态程序只要发一条指令后拷贝过程直接在内核态进行(既零拷贝,相比于传统FileInputStream需要读到用户态内存 更节省时间)。
• NIO中的DirectBuffer 自身是一个Java对象,在Java堆中;而这个对象中有个long类型字段address,记录着一块调用 系统malloc() 申请到的用户态的native memory。 FileChannel中的write(ByteBuffer src)方法中,如果传入的参数是HeapBuffer类型,则会将HeapBuffer里的数据拷贝到临时申请一块DirectBuffer中,而不是直接进行数据传输,这是因为HotSpot VM里的GC除了CMS之外都是要移动对象的(compacting GC),如果要把一个HeapBuffer里的 byte[] 对象的引用传给native代码(这里传给系统API的write函数),就必须要保证native代码在访问的时候这个byte[]对象不能被移动,也就不能GC(影响性能),所以就额外申请一个native memory(不在GC范围内)并将数据从HeapBuffer拷贝到DirectBuffer,然后传给系统函数write。(而传入的参数如果是DirectBuffer类型,免去了堆内至堆外的复制过程)。
如果引用a指向程序中创建了DirectByteBuffer类对象实例(背后指向一个堆外内存),其内部成cleaner = Cleaner.create (a , new Deallocator(base, size, cap));(Cleaner继承自PhantomReference),jdk实现GC时对几种引用类型有定制化开发,在判断a没有被其他变量强引用(只被cleaner虚引用着)后将a置于pending上,再通知到一个ReferenceHandler线程从pending取下a放到与之相关的ReferenceQueue里,判断a是否是Cleaner,如果是就会调用.clean()方法 取出a(a指向的对象可以被GC掉了), 触发new Deallocator里的run方法回收堆外直接内存。
byteBuffer.flip() 是在往byteBuffer内存池里写完数据,需要开始读它的时候,将limit设为当前postion(以后读到limit就可以了),并将postion复位到0。Java NIO学习笔记之二-图解ByteBuffer - 黄亿华的个人空间 - OSCHINA - 中文开源技术交流社区 nio DirectByteBuffer如何回收堆外内存 Java Reference 源码分析 - Jabnih - 博客园 堆外内存 之 DirectByteBuffer 详解 - 简书