NIO中缓冲区是数据传输的基础,JDK通过ByteBuffer实现,Netty框架中并未采用JDK原生的ByteBuffer,而是构造了ByteBuf. ByteBuf对ByteBuffer做了大量的优化,比如说内存池,零拷贝,引用计数(不依赖GC),本文主要是分析这些优化,学习这些优化思想,学以致用,在实际工程中,借鉴这些优化方案和思想. 直接内存和堆内存 首先先讲一下这里面需要用的基础知识,在JVM中 内存可分为两大块,一个是堆内存,一个是直接内存.这里简单介绍一下 堆内存: 堆内存是Jvm…
前言 到目前为止,我们知道Nio当中有三个最最核心的组件,分别是:Selelctor,Channel,Buffer.在Netty基础系列(3) --彻底理解NIO 这一篇文章中只是进行了大致的介绍. 我们现在来深入理解一下Buffer在 堆内创建内存 和 堆外创建内存 的底层原理,与 零拷贝 的具体实现. Buffer Buffer是一个抽象类,首先我们来看看Buffer有哪些实现类. 我们从上面这张截图可以看出,Buffer的直接子类有7种.除了Java中Boolean类型.剩余的7种基本类型…
/********************************************************* 在一些不确定内存总占用量的情形下,频繁的使用new申请内存,再通过链表 进行索引似乎是很常规的做法.自然,也很难做到随机定位. 下面的内存池类是用二层索引表来对内存进行大块划分,任何一个块均只需索 引3次即可定位. 索引数量,每索引块的分配单元数量,以及分配单元的字节长度均需为2的整数 次幂(为了运算时的效率) //by:www.frombyte.com zhangyu(zhan…
一.直接缓存 这个例子的区别就是 ByteBuffer.allocateDirect(512); 进入allocateDirect方法 进入DirectByteBuffer构造函数 Native方法:unsafe.allocateMemory public native long allocateMemory(long var1); 问题:为什么HeapByteBuffer要拷贝数据,而不是由操作系统之间操作这块数据? 因为JVM会进行垃圾回收,根据垃圾回收算法,被标记的控件会被回收,然后重新压…
重点: 1.0拷贝需要系统支持. 普通内存模型: java线程内存 --> 操作系统内存 --> 硬盘 直接内存模型: java --> 操作系统内存 --> 硬盘 两者对比,少了一步:直接内存直接操作系统内存,少了java线程内存到操作系统内存拷贝的这一步,所以提升了效率. 代码: java.nio.channels.FileChannel#transferTo 示例: channel.transferTo(0,channel.size(),OutputChannel); 内存映…
Netty中的内存管理应该是借鉴了FreeBSD内存管理的思想--jemalloc.Netty内存分配过程中总体遵循以下规则: 优先从缓存中分配 如果缓存中没有的话,从内存池看看有没有剩余可用的 如果已申请的没有的话,再真正申请内存 分段管理,每个内存大小范围使用不同的分配策略 我们先总体上看下Netty内存分配的策略,然后再结合对应的数据结构来看看每种策略的具体实现. 总体分配策略 netty根据需要分配内存的大小使用不同的分配策略,主要分为以下几种情况(pageSize默认是8K, chun…
io.netty.buffer.PooledByteBuf<T>使用内存池中的一块内存作为自己的数据内存,这个块内存是PoolChunk<T>的一部分.PooledByteBuf<T>是一个抽象类型,它有4个派生类: PooledHeapByteBuf, PooledUnsafeHeapByteBuf 使用堆内存的PooledByteBuffer<byte[]>. PooledDirectByteBuf, PooledUnsafeDirectByteBuf…
前言 上一节(堆外内存与零拷贝)当中我们从jvm堆内存的视角解释了一波零拷贝原理,但是仅仅这样还是不够的. 为了彻底搞懂零拷贝,我们趁热打铁,接着上一节来继续讲解零拷贝的底层原理. 感受一下NIO的速度 之前的章节中我们说过,Nio并不能解决网络传输的速度.但是为什么很多人却说Nio的速度比传统IO快呢? 没错,zero copy.我们先抛出一个案例,然后根据案例来讲解底层原理. 首先,我们实现一个IO的服务端接受数据,然后分别用传统IO传输方式和NIO传输方式来直观对比传输相同大小的文件所耗费…
今天开始写一些高并发实战系列. 本系列主要讲两大主流框架: Netty和Quasar(java纤程库) 先介绍netty吧,netty是业界比较成熟的高性能异步NIO框架. 简单来说,它就是对NIO2的封装,但提供了更好用,bug更少的API. 为什么netty能提供高性能?核心要点有以下两点: 1.Netty基于NIO2的事件驱动模式 2.零拷贝 先说,事件驱动模式吧,这个好理解,我们慢慢分解: java原来IO操作都是阻塞的,一个IO请求一个线程,多个IO请求就要多个线程,很消耗资源. 现在…
一.先理解内核空间与用户空间 Linux 按照特权等级,把进程的运行空间分为内核空间和用户空间,分别对应着下图中, CPU 特权等级分为4个,Linux 使用 Ring 0 和 Ring 3. 内核空间(Ring 0)具有最高权限,可以直接访问所有资源,: 用户空间(Ring 3)只能访问受限资源,不能直接访问内存等硬件设备,必须通过系统调用陷入到内核中,才能访问这些特权资源. 上面的Ring图可以简化成: 内核从本质上看是一种软件--控制计算机的硬件资源,并提供上层应用程序运行的环境.用户态即…
1.前言 之前的章节已经将启动demo中能看见的内容都分析完了,Netty的一个整体样貌都在第8节线程模型最后给的图画出来了.这些内容解释了Netty为什么是一个异步事件驱动的程序,也解释了Netty的线程模型的高效,但是并没有涉及到的一个方面就是Handler的解析过程.通过前面的知识点我们都应该明白了Handler用于对获取的数据按照相关协议进行解析,Java的NIO都是通过buffer完成的读写的,这里关于Netty的另一个高效性却没有涉及,那就是内存管理,这个阶段发生在handler读取…
Java的堆外内存本来是高贵而神秘的东西,只在一些缓存方案的收费企业版里出现.但自从用了Netty,就变成了天天打交道的事情,毕竟堆外内存能减少IO时的内存复制,不需要堆内存Buffer拷贝一份到直接内存中,然后才写入Socket中:而且也没了烦人的GC. 好在,Netty所用的堆外内存只是Java NIO的 DirectByteBuffer类,通读一次很快.还有一些sun.misc.*的类木有源码,要自己跑去OpenJdk那看个明白. 1. 堆外内存的创建 在DirectByteBuffer中…
摘要: 在Netty中,通常会有多个IO线程独立工作,基于NioEventLoop的实现,每个IO线程负责轮询单独的Selector实例来检索IO事件,当IO事件来临的时候,IO线程开始处理IO事件.最常见的IO事件即读写事件,那么这个时候就会涉及到IO线程对数据的读写问题,具体到NIO方面即从内核缓冲区读取数据到用户缓冲区或者从用户缓冲区将数据写到内核缓冲区.NIO提供了两种Buffer作为缓冲区,即DirectBuffer和HeapBuffer.这篇文章主要在介绍两种缓冲区的基础之上再介绍N…
PooledByteBufAllocator负责初始化PoolArena(PA)和PoolThreadCache(PTC).它提供了一系列的接口,用来创建使用堆内存或直接内存的PooledByteBuf对象,这些接口只是一张皮,内部完全使用了PA和PTC的能力.初始化过程分两个步骤,首先初始化一系列的默认参数,然后初始化PTC对象和PA数组. 默认参数和它们的值 DEFAULT_PAGE_SIZE: PoolChunk中的page的大小-pageSize,  使用-Dio.netty.alloc…
内存池的内存规格: 在前面的源码分析过程中,关于内存规格大小我们应该还有些印象.其实在Netty 内存池中主要设置了四种规格大小的内存:tiny 是指0-512Byte 之间的规格大小,small 是指512Byte-8KB 之间的规格大小,normal 是指8KB-16MB 之间的规格大小,huge 是指16MB 以上.为什么Netty 会选择这些值作为一个分界点呢?其实在Netty 底层还有一个内存单位的封装,为了更高效地管理内存,避免内存浪费,把每一个区间的内存规格由做了细分.默认情况下,…
2. 垃圾收集器与内存分配策略 垃圾收集(Garbage Collection, GC)是JVM实现里非常重要的一环,JVM成熟的内存动态分配与回收技术使Java(当然还有其他运行在JVM上的语言,如Scala等)程序员在提升开发效率上获得了惊人的便利.理解GC,对于理解JVM和Java语言有着非常重要的作用.并且当我们需要排查各种内存溢出.内存泄漏问题时,当垃圾收集称为系统达到更高并发量的瓶颈时,只有深入理解GC和内存分配,才能对这些"自动化"的技术实施必要的监控和调节. GC主要需…
我们知道,Netty使用直接内存实现Netty零拷贝以提升性能, 但直接内存的创建和释放可能需要涉及系统调用,是比较昂贵的操作,如果每个请求都创建和释放一个直接内存,那性能肯定是不能满足要求的. 这时就需要使用内存池. 即从系统中申请一大块内存,再在上面分配每个请求所需的内存. Netty中的内存池主要涉及PoolArena,PoolChunk与PoolSubpage. 本文主要分析PoolArena的作用与实现. 源码分析基于Netty 4.1.52 接口关系 ByteBufAllocator…
https://michaelscodingspot.com/cpu-bound-memory-bound/ 优化.NET 应用程序 CPU 和内存的11 个实践 凡事都有其限度,对吧?汽车只能开这么快,进程只能使用这么多内存,程序员只能喝这么多咖啡.我们的生产力受到资源的限制,我们有能力更好或更差地利用它们.尽可能接近其极限使用我们的每一种资源是我们的目标,我们希望使用我们的 CPU 和内存的每一点,否则我们会为昂贵的机器多付钱. 然而,若是我们使用了过多的资源,我们就有可能导致性能问题.服务…
原文:[百度地图API]今日小年大进步,齐头共进贺佳节--API优化升级上线,不再增加内存消耗 任务描述: 今天是2011年01月26日,小年夜.百度地图API在小年夜献给广大API爱好者一份给力的礼物!那就是,百度地图API内存消耗优化升级了! 此次API优化升级后,内存消耗保持平稳,绝大部分测试中,内存消耗趋于一条直线.(如图所示) 如何实现: a)         本次测试全部采用IE6浏览器: b)         本次测试的覆盖物全部采取随机方式创建: c)         本次测试覆…
Kafka集群优化篇-调整broker的堆内存(heap)案例实操 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.查看kafka集群的broker的堆内存使用情况 1>.使用jstat查看gc的信息([root@kafka116 ~]# jstat -gc 12698 1s 30) 参数说明:S0C:第一个幸存区的大小 S1C:第二个幸存区的大小 S0U:第一个幸存区的使用大小 S1U:第二个幸存区的使用大小 EC:伊甸园区的大小 EU:伊甸园区的使用大小 OC:老年代大…
前面两章分析的PoolChunk和PoolSubpage,从功能上来说已经可以直接拿来用了.但直接使用这个两个类管理内存在高频分配/释放内存场景下会有性能问题,PoolChunk分配内存时算法复杂度最高的是allocateNode方法,释放内存时算法复杂度最高的是free方法. PoolChunk中二叉树的高度是maxOrder,  那么算法负责度是O(maxOrder),netty默认的maxOrder是11.另外,PoolChunk不是线程安全的,如果在多线程环境下需要加锁调用,这个开销比算…
一.为什么要实现内存管理? Netty 作为底层网络通信框架,网络IO读写必定是非常频繁的操作,考虑到更高效的网络传输性能,堆外内存DirectByteBuffer必然是最合适的选择.堆外内存在 JVM 之外,在有效降低 JVM GC 压力的同时,还能提高传输性能. 堆外内存是非常宝贵的资源,申请和释放都是高成本的操作,使用不当还可能造成严重的内存泄露等问题 .那么进行池化管理,如使用Netty提供的PooledUnsafeDirectByteBuf,多次重用是比较有效的方式.从申请内存大小的角…
PoolArena实现了用于高效分配和释放内存,并尽可能减少内存碎片的内存池,这个内存管理实现使用PageRun/PoolSubpage算法.分析代码之前,先熟悉一些重要的概念: page: 页,一个页是可分配的最小的内存块单元,页的大小:pageSize = 1 << n (n <= 12). chunk: 块,块是多个页的集合.chunkSize是块中所有page的pageSize之和. Tiny: <512B的内存块. Small: >=512B, <pageSi…
内存池ByteBuf 内存回收: 在前面的章节中我们有提到, 堆外内存是不受JVM 垃圾回收机制控制的, 所以我们分配一块堆外内存进行ByteBuf 操作时, 使用完毕要对对象进行回收, 本节就以PooledUnsafeDirectByteBuf 为例讲解有关内存分配的相关逻辑.PooledUnsafeDirectByteBuf 中内存释放的入口方法是其父类AbstractReferenceCountedByteBuf 中的release()方法: public boolean release(…
零复制概念: " 零复制"描述了计算机操作,其中CPU不执行将数据从一个存储区复制到另一个存储区的任务.通过网络传输文件时,通常用于节省CPU周期和内存带宽. WIKI的定义中,我们看到 "零复制" 是指计算机操作的过程,不需要消耗CPU资源来在内存之间进行数据复制.它通常是指计算机在网络上发送文件时,不需要将文件的内容复制到用户空间并将其直接传输到内核空间中的网络的方式. ① 非零副本(传统的数据复制方法): → :CPU Copy(慢) → :DMA(直接内存访…
此文章已同步发布在我的 segmentfault 专栏. 根据 Wiki 对 Zero-copy 的定义: "Zero-copy" describes computer operations in which the CPU does not perform the task of copying data from one memory area to another. This is frequently used to save CPU cycles and memory ban…
转载:https://www.jianshu.com/p/1d1fa2fe1ed9 此文章已同步发布在我的 segmentfault 专栏. 根据 Wiki 对 Zero-copy 的定义: "Zero-copy" describes computer operations in which the CPU does not perform the task of copying data from one memory area to another. This is frequen…
根据 Wiki 对 Zero-copy 的定义: "Zero-copy" describes computer operations in which the CPU does not perform the task of copying data from one memory area to another. This is frequently used to save CPU cycles and memory bandwidth when transmitting a fi…
Netty 零拷贝(二)NIO 对零拷贝的支持 Netty 系列目录 (https://www.cnblogs.com/binarylei/p/10117436.html) 非直接缓冲区(HeapByteBuffer):在 JVM 内存上分配一个字节数组 byte[] hb 直接缓冲区(DirectByteBuffer):保存一个指向系统内核的地址 long address 一.非直接缓冲区和直接缓冲区 (1) Buffer 分配 // 分配非直接缓冲区 public static ByteBu…
Netty 零拷贝(一)Linux 零拷贝 本文探讨 Linux 中主要的几种零拷贝技术以及零拷贝技术适用的场景. 一.几个重要的概念 1.1 用户空间与内核空间 操作系统的核心是内核,独立于普通的应用程序,可以访问受保护的内存空间,也有访问底层硬件设备的所有权限.为了保证用户进程不能直接操作内核 (kernel),保证内核的安全,操作系统将虚拟空间划分为两部分,一部分为内核空间,一部分为用户空间. 1.2 IO 两个流程 网络 IO 的本质是 socket 的读取,socket 在 linux…