IO

1、文件IO


JAVA-IO.png

使用 Off Heap 堆外内存,减少了堆内向堆外拷贝过程,效率要高一些,

堆内:JVM 堆内内存。

堆外:JVM堆外,JAVA 进程堆内。

mapped映射:是 mmap 调用的一个进程和内核共享的内存区域,且这个内存区域是 PageCache 到文件的映射。

性能表现 mapped > off heap > on heep

Java 普通IO,每次调用写操作,都会向 OS PageCache 溢写,而 Buffered IO(8KB),向其写入时,仅写入到 JVM 内存,知道写满之后,才会溢写到 PageCache。

对比来看,Buffered 少了很多 system callint 0x80,因此效率高很多。

ByteBuffer

内存分配

  • 堆内分配:ByteBuffer.allocate(1024)
  • 堆外分配:ByteBuffer.allocateDirect(1024)

函数

  • put:写入数据,并移动 position 指针。
ByteBuffer-PUT.png
  • flip:由写模式切换到读模式。读模式下调用,会使 limit 指向当前 position 位置,造成指针错乱。
ByteBuffer-FLIP.png
  • get:读取数据,并移动 position 指针。读操作应在 flip 操作后执行,否则可能读取到错误数据。
ByteBuffer-GET.png
  • compact:压缩数据,并切换到写模式。如果在写模式调用,数据会错乱,因为 limit 指向 了 tail。
ByteBuffer-COMPACT.png
  • mark - reset:标记 position 位置,重置 position 到 mark 位置,不会切换读写模式,读写模式都可用。
ByteBuffer-MARK-RESET.png
  • slice:创建一个新的字节缓冲区,其内容是给定缓冲区内容的共享子序列。

    新缓冲区的内容将从该缓冲区的当前位置开始。对该缓冲区内容的更改将在新缓冲区中可见,反之亦然。这两个缓冲区的位置,限制和标记值将是独立的。

    新缓冲区的位置将为零,其容量和限制将为该缓冲区中剩余的浮点数,并且其标记将不确定。当且仅当该缓冲区是直接缓冲区时,新缓冲区才是直接缓冲区;当且仅当该缓冲区是只读缓冲区时,新缓冲区才是只读缓冲区。

  • rewind:清除 mark 标记,并将 position 指针 重置为0。

  • clear:重置缓冲区,清除 mark 标记,重置 position 指针,重置 limit 指针,回归写模式。

RandomAccessFile

Mode 说明
r 打开文件仅仅是为了读取数据,如果尝试调用任何写入数据的操作都会造成返回IOException错误信息的问题。
rw 打开文件用于读写两种操作,如果文件本身并不存在,则会创建一个全新的文件。
rwd 打开文件用于读写两种操作,这点和 rw 的操作完全一致,但是只会在 cache 满,或者调用 RandomAccessFile.close() 的时候才会执行内容同步操作。
rws 在 rwd 的基础上对内容同步的要求更加严苛,每write修改一个byte都会直接修改到磁盘中。
RandomAccessFile raf = new RandomAccessFile(new File("/path/to/file"), "rw");
// 写数据
raf.write(new byte[5]);
// 移动指针
raf.seek(0L);
// 跳过字节
raf.skipBytes(1);
// 读数据 off:输入数组偏移量 len:读字节数
raf.read(new byte[10], 0, 10);
// 关闭并写盘
raf.close();

FileChannel

RandomAccessFile raf = new RandomAccessFile(new File("/path/to/file"), "rw");
FileChannel channel = raf.getChannel();
// Zero Copy
channel.transferTo(position, count, target);
channel.transferFrom(src, position, count);

MappedByteBuffer

  • 不通过系统调用,数据直接到达 PageCache。
  • mmap 的内存映射,依然受内核 pageCache 体系所约束。
  • DirectIO 是忽略内核的 PageCache,Java 没有直接使用内核 DirectIO 的支持,需要C程序JNI扩展库。
  • MappedByteBuffer 只是交给程序开辟自己的字节数组充当 PageCache,仍需要程序动用代码维护一致性/Dirty等一系列问题。
MapMode 说明
FileChannel.MapMpde.READ_ONLY Mode for a read-only mapping. 只读模式。
FileChannel.MapMpde.READ_WRITE Mode for a read/write mapping. 读写模式。
FileChannel.MapMpde.PRIVATE Mode for a private (copy-on-write) mapping. 堆内存更改不会写入文件。
RandomAccessFile raf = new RandomAccessFile(new File("/path/to/file"), "rw");
FileChannel channel = raf.getChannel();

MappedByteBuffer map = channel.map(FileChannel.MapMode.READ_WRITE, 0, 4090);
// 其余操作函数可参考 ByteBuffer
map.put(new byte[10]);
// PC数据写入存储设备
buffer.force();

2、TCP网络IO


服务端 LISTEN 状态端口号,最多65535个。

服务端无需为 Client 连接分配随机端口号,只要四元组(源IP、源端口、目标IP、目标端口)不同,就可以确定一个连接。

三次握手是内核级的,ServerSocket 启动之后,客户端连接时,无需等待 server.accept() 即可完成三次握手,建立连接。

因为客户端连接是连接层业务,不需要等待应用层响应。

客户端连接建立之后,server.accept() 之前,OS 仅仅开辟资源,并不会分配 FD。

server.accept() 之后,OS 才会创建 FD,FD 在 Java 中体现为 Socket 对象。

ServerSocket配置

  • BACK_LOG:未 accept 的连接队列长度,超过此数量的连接,在 netstat 中体现为 SYN_RECV 状态。

  • SO_TIMEOUT:server.accept() 超时配置,超过阈值未收到连接请求,会跑出 SocketTimeoutException 异常,但并不会造成 server 崩溃。

  • RECEIVE_BUFFER_SIZE:最大接收窗口,默认 8192。最终数值由三次握手之后双方最小缓冲区为基准。

  • REUSE_ADDRESS:端口重用。如果禁用,在程序关闭后,端口可能会继续占用一段时间,如果此时立刻重启程序,会抛出异常。

    绑定到相同端口的程序,必须全部启用该配置,才可重用端口,设置此参数必须在程序绑定到一个本地端口之前调用。

Socker配置

  • KEEP_ALIVE:TCP连接空闲时是否需要向对方发送探测包,依赖于底层的TCP模块实现的,Java中只能设置是否开启,不能设置其详细参数,依赖于系统配置。

  • SO_TIMEOUT:在与此 Socket 关联的 InputStream 上调用 read() 将只阻塞此时间长度,超时将引发 SocketTimeoutException,但 socket 不会崩溃。

  • OOB_INLINE:TCP的紧急指针,一般不建议使用,且不同的TCP/IP实现不同。

    虽然 Socket.sendUrgentData() 的参数是 int 类型,但只有这个int类型的低字节被发送,其它的三个字节被忽略。

    客户端和服务端必须同时开启,否则无法使用 Socket.sendUrgentData() 发送数据。

  • RECEIVE_BUFFER_SIZE:最大接收窗口,默认 8192。最终数值由三次握手之后双方最小缓冲区为基准。

  • SEND_BUFFER_SIZE:最大发送窗口,默认 8192。最终数值由三次握手之后双方最小缓冲区为基准。

  • REUSE_ADDRESS:端口重用。如果禁用,在程序关闭后,端口可能会继续占用一段时间,如果此时立刻重启程序,会抛出异常。

    绑定到相同端口的程序,必须全部启用该配置,才可重用端口,设置此参数必须在程序绑定到一个本地端口之前调用。

  • SO_LINGER:控制 Socket 关闭行为,

    • 默认情况执行 Socket.close() 立即返回,但底层的连接不会立即关闭,会延迟一段时间,直到数据发送完成,才会真正的关闭 Socket,断开连接。
    • Socket.setSoLinger(true, 0):执行 Socket.close() 会立即返回,底层 Socket 立即关闭,所有未发送数据被丢弃。
    • Socket.setSoLinger(true, 3600):执行 Socket.close() 会进入阻塞状态,底层 Socket 尝试发送剩余数据,直到如下条件解除阻塞状态:
      1. 剩余数据发送完成。
      2. 剩余数据未发送完成,但阻塞超过 3600毫秒,立即返回,且丢弃剩余数据。
  • TCP_NO_DELAY:默认 false,为启用 Nagle算法。Nagle 算法的立意是,避免网络中充塞小封包,提高网络的利用率。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,937评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,503评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,712评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,668评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,677评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,601评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,975评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,637评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,881评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,621评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,710评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,387评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,971评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,947评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,189评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,805评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,449评论 2 342

推荐阅读更多精彩内容