>>分享IT从业人员的工作经验、生活感悟,心得 书籍支持  卫琴直播  品书摘要  在线测试  资源下载  联系我们
发表一个新主题 开启一个新投票 回复文章 您是本文章第 30452 个阅读者 刷新本主题
 * 贴子主题:  面试中被问到零拷贝的问题 回复文章 点赞(0)  收藏  
作者:flybird    发表时间:2025-11-08 07:58:43     消息  查看  搜索  好友  邮件  复制  引用

"狼哥,面试又跪了,碰到了知识盲区"

"哪个?"

"一面还可以,二面面试官问我零拷贝的原理,懵逼了...这块内容没去研究过"

"哦,这个知识点,我之前应该有讲过,你没注意到?"

"这东西工作中用不到,可能被我忽略了"

"啧啧啧..."

"哎,有空和我大概讲讲?"

"先从简单开始,实现下这个场景:从一个文件中读出数据并将数据传到另一台服务器上?"

"为啥写这个?"

"你先写"

"行..."

1分钟后

"我写了伪代码"
File.read(file, buf, len);
Socket.send(socket, buf, len);

  "这里涉及到了几次数据拷贝?"

"2次?磁盘拷贝到内存,内存拷贝到Socket?"

"emmm,怪不得挂了,一点不冤。"

"这种方式一共涉及了4次数据拷贝,知道用户态和内核态的区别吗?"

"了解"

"行,文字有点干瘪,你先看这个图"

  
点击在新窗口中浏览原图
CTRL+鼠标滚轮放大或缩小

image.png

1、应用程序中调用

read()

方法,这里会涉及到一次上下文切换(用户态->内核态),底层采用DMA(direct memory access)读取磁盘的文件,并把内容存储到内核地址空间的读取缓存区。

2、由于应用程序无法读取内核地址空间的数据,如果应用程序要操作这些数据,必须把这些内容从读取缓冲区拷贝到用户缓冲区。这个时候,

read()

调用返回,且引发一次上下文切换(内核态->用户态),现在数据已经被拷贝到了用户地址空间缓冲区,这时,如果有需要,应用程序可以操作修改这些内容。

3、我们最终目的是把这个文件内容通过Socket传到另一个服务中,调用Socket的

send()

方法,这里又涉及到一次上下文切换(用户态->内核态),同时,文件内容被进行第三次拷贝,被再次拷贝到内核地址空间缓冲区,但是这次的缓冲区与目标套接字相关联,与读取缓冲区没有半点关系。

4、

send()

调用返回,引发第四次的上下文切换,同时进行第四次的数据拷贝,通过DMA把数据从目标套接字相关的缓存区传到协议引擎进行发送。

"在整个过程中,过程1和4是由DMA负责,并不会消耗CPU,只有过程2和3的拷贝需要CPU参与,整明白了?"

"我消化一下..."

半小时后...

"狼哥,这个过程,感觉好几次的数据拷贝都是多余的,很影响性能啊"

"对,所以才有了零拷贝技术"

"具体咋实现?"

"慢慢来,如果在应用程序中,不需要操作内容,过程2和3就是多余的,如果可以直接把内核态读取缓存冲区数据直接拷贝到套接字相关的缓存区,是不是可以达到优化的目的?"



点击在新窗口中浏览原图
CTRL+鼠标滚轮放大或缩小


这种实现,可以有以下几点改进:
  • 上下文切换的次数从四次减少到了两次
  • 数据拷贝次数从四次减少到了三次(其中DMA copy 2次,CPU copy 1次)
"怎么实现?"

"在Java中,正好FileChannel的transferTo() 方法可以实现这个过程,该方法将数据从文件通道传输到给定的可写字节通道, 上面的

file.read()



socket.send()

调用动作可以替换为

transferTo()

调用"


public void transferTo(long position, long count, WritableByteChannel target);

  在 UNIX 和各种 Linux 系统中,此调用被传递到

sendfile()

系统调用中,最终实现将数据从一个文件描述符传输到了另一个文件描述符。

"确实改善了很多,但还没达到零拷贝的要求,还有其它黑技术吗?"

"对的,如果底层网络接口卡支持收集操作的话,就可以进一步的优化。"

"怎么优化?"

在 Linux 内核 2.4 及后期版本中,针对套接字缓冲区描述符做了相应调整,DMA自带了收集功能,对于用户方面,用法还是一样的,但是内部操作已经发生了改变:



点击在新窗口中浏览原图
CTRL+鼠标滚轮放大或缩小
  • 第一步,transferTo() 方法引发 DMA 将文件内容拷贝到内核读取缓冲区。
  • 第二步,把包含数据位置和长度信息的描述符追加到套接字缓冲区,避免了内容整体的拷贝,DMA 引擎直接把数据从内核缓冲区传到协议引擎,从而消除了最后一次 CPU参与的拷贝动作。
----------------------------
原文链接:https://www.jianshu.com/p/2581342317ce



程序猿的技术大观园:www.javathinker.net
  Java面向对象编程-->Java语言的基本语法和规范
  JavaWeb开发-->集合(上)
  JSP与Hibernate开发-->JavaWeb应用入门(Ⅱ)
  Java网络编程-->Web运作原理(Ⅳ)
  精通Spring-->JPA API的高级用法
  Vue3开发-->映射一对多关联关系
  面试多次被拒,‘宅家苦修’61天,我收到了蚂蚁金服P7级的of...
  【数据说话】机器学习工程师要掌握那些技能,前景如何
  本科生如何才能进入腾讯,阿里等一流的互联网公司?
  “面试造航母,工作拧螺丝”,面了4家公司,感慨万千(Java岗...
  解密初、中、高级程序员的进化之路(前端)
  人工智能可能会弄虚作假的负面影响,看看这张照片就知道了!
  5G时代如何赋予软件应用更多可能
  IT职场法则七条——献给正在努力奋斗的你们
  花2万去培训,真的能月薪上万吗?
  一位程序员的创业故事
  Java学习之路:不走弯路就是捷径
  赞美的话,公开说;批评的话,私下讲
  如何从码农晋升为码神
  一个五年 Android 开发者百度、阿里、聚美、映客的面试心经
  职业生涯中的自我管理
  更多...
 IPIP: 已设置保密
楼主      
1页 0条记录 当前第1
发表一个新主题 开启一个新投票 回复文章


中文版权所有: JavaThinker技术网站 Copyright 2016-2026 沪ICP备16029593号-2
荟萃Java程序员智慧的结晶,分享交流Java前沿技术。  联系我们
如有技术文章涉及侵权,请与本站管理员联系。