1.3.计算机特性

写时复制机制(copy-on-write)

博客

1.Linux写时复制技术(copy-on-write):

https://www.cnblogs.com/biyeymyhjob/archive/2012/07/20/2601655.html

Linux COW机制:

按照传统的方法,fork()命令会直接将父进程的数据拷贝到子进程中,拷贝完之后,父进程和子进程之间的数据段和堆栈是相互独立的,但是往往子进程都会执行exec()操作来实现自己的逻辑,这样的话就会导致创建子进程时复制过去的数据都会被清空,没有作用。

COW利用这个特点,使fork()出来的子进程与父进程共享内存空间,kernel会把父进程中的所有内存页的权限设成read-only,然后子进程的地址空间指向父进程。当父子进程都只是读取内存空间时相安无事,当其中某个进程写内存时,CPU硬件检测到内存页是read-only的,于是触发页中断异常,陷入kernel的一个中断历程。中断历程中,kernel就会把触发的异常的页复制一份,于是父子进程各自持有独立的一份。

COW好处:可以减少分配和复制大量资源是带来的瞬时延迟;可减少不必要的资源分配,比如fork()进程时,并不是所有的页面都需要复制,父进程的代码段和只读数据都不允许修改,所以无需复制。

COW缺点:如果在fork()之后,父子进程都需要进行读写操作,那么会产生大量的分页错误(页异常中断page-fault),这样得不偿失。

写时复制思想的延伸:写时复制是一种计算机程序设计领域的优化策略。其核心思想是,如果有多个调用者同时请求相同的资源,他们会共同获取相同的指针指向相同的资源,直达搜某个调用者试图修改资源的内容时,系统才会真正复制一份专用副本给调用者。此做法的优点是只有调用者修改资源时,才会创建副本,否则,多个调用者可以共享同一份资源。

应用场景

Redis:持久化时,如果执行BGSAVE或BGREWRITEAOF命令,redis会fork出一个子进程来持久化数据文件;总体来说,Redis还是读操作较多。如果子进程存在期间,发生了大量的写操作,那可能会出现很多页中断异常(page-fault),这样就会花费很多性能在复制数据上;而在Hash结构进行扩/缩容时的rehash操作时,写操作时无法避免的,所以redis在fork出子进程时,将负载因子阈值由1提高到5,尽量减少写操作,避免不必要的内存写数据。

文件系统:copy on write在对数据修改的时候,不会直接在原来的位置上进行操作,而是重新找个位置修改,这样的好处是一旦断电,重启之后不需要做Fsck(file system check)。能保证数据的完整性,掉电的话容易恢复。

Java源码:JUC中的CopyOnWriteArraySet和CopyOnWriteArrayList。

JAVA中的copy-on-write容器:

JAVA中的copy-on-write容器_滴哩哩哩滴哩哩哩哒哒的博客-CSDN博客

零拷贝

1.零拷贝原理详解:

零拷贝原理详解_零拷贝的原理_Tasdily的博客-CSDN博客

  • 零拷贝

传统的IO流程:

假设我们读取文件再发送,buffer = File.read(); Socket.send(buffer); 经历以下的传输流程:

    1. 第一次,将磁盘文件读取到操作系统内核缓冲区;
    2. 第二次,将内核缓冲区的数据,copy到application引用程序的buffer;
    3. 第三次,将application应用程序buffer中的数据,copy到socket网络发送缓冲区中(属于操作系统内核的缓冲区);
    4. 第四次,将socket buffer的数据,copy到网卡,用网卡进行网络传输。

零拷贝则是指读取文件至内核空间后,不需要做其他处理,直接用网络发送出去,省掉第二次和第三次拷贝。

mmap(Memory Mapped Files)

博客

认真分析mmap:是什么 为什么 怎么用?https://www.cnblogs.com/huxiao-tee/p/4660352.html

【深入浅出Linux】关于mmap的解析:【深入浅出Linux】关于mmap的解析 - 简书

mamp实现原理浅析:mmap实现原理浅析 - 知乎

mmap-用户空间与内核空间:mmap - 用户空间与内核空间_luckywang1103的博客-CSDN博客

简述

将磁盘文件映射到内存,用户通过修改内存就能修改磁盘文件。mmap操作提供了一种机制,让用户程序直接访问设备内存,这种机制,相比较在用户空间和内核空间互相拷贝数据,效率更高。

工作原理

直接利用操作系统的Page来实现文件到内存的直接映射。完成映射之后你对服务内存的操作会被同步到磁盘上(操作系统在适当的时候)。通过mmap机制,进程就像读写磁盘一样读写内存(当然是虚拟化内存),也不必关心内存的大小有虚拟内存为我们兜底。使用这种方式,可以很大的提升I/O性能,省去了用户空间到内核空间的复制的开销。

磁盘上的文件通过mmap函数可直接通过DMA被拷贝到内核缓冲区中,接着操作系统会与与应用程序共享这块内核缓冲区,应用程序在通过write()函数直接将内核缓冲区中的内容拷贝到socket缓冲区,最后,socket缓冲区在把数据发送到网卡上。

在linux中,我们可以使用mmap用来在进程虚拟内存地址空间中分配地址内存,创建和物理内存的映射关系。

缺点

当使用mmap读取文件时,假如文件被其他进程截断(truncate)时,write()系统调用因为访问非法地址而被SIGBUS信号终止,SIGBUS信号默认杀死你的进程而产生一个coredump。

SIGBUS解决方式:为SIGBUS信号建立信号处理程序,当遇到SIGBUS时,信号程序简单处理,write()会返回遇到中断之前已经写入的字节数,并且将error处理为success,但实际上你并没有处理掉异常;使用文件租借锁。

sendfile:

缺点:规定in_fd必须是输出文件的描述符,而out_fd必须指向一个套接字,反之则不行,说明sendfile只允许从磁盘到套接字的传送。

splice:

缺点:splice支持文件从fd_in拷贝len长度到fd_out,但是其规定一方描述符必须是管道设备。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值