1.MappedByteBuffer VS FileChannel å°å¼ºå°å¼±ï¼
2.èè微信 Xlog
3.C++/C 内存分配-malloc/mmap/syscall深度解析以及性能测试
4.零拷贝技术及在Java中应用
5.Linux内核虚拟内存管理之匿名映射缺页异常分析
6.Linux内核黑科技——mmap实现详解
MappedByteBuffer VS FileChannel å°å¼ºå°å¼±ï¼
Java å¨ JDK 1.4 å¼å ¥äº ByteBuffer ç NIO ç¸å ³çç±»ï¼ä½¿å¾ Java ç¨åºåå¯ä»¥æå¼åºäº Stream ï¼ä»è使ç¨åºäº Block çæ¹å¼è¯»åæ件ï¼å¦å¤ï¼JDK è¿å¼å ¥äº IO æ§è½ä¼åä¹çââ é¶æ·è´ sendFile å mmapãä½ä»ä»¬çæ§è½ç©¶ç«æä¹æ ·ï¼ å RandomAccessFile æ¯èµ·æ¥ï¼å¿«å¤å°ï¼ ä»ä¹æ åµä¸å¿«ï¼å°åºæ¯ FileChannel å¿«è¿æ¯ MappedByteBuffer å¿«......(é¶æ·è´åè Zero Copy I: User-Mode Perspective )
天åï¼é®é¢å¤ªå¤äºï¼ï¼ï¼ï¼ï¼ï¼
让æä»¬æ ¢æ ¢åæã
æ们ç¥éï¼Java ä¸çæå¾å¤ MQï¼ActiveMQï¼kafkaï¼RocketMQï¼å»åªå¿ MQï¼èä»ä»¬åæ¯ Java ä¸çä½¿ç¨ NIO é¶æ·è´ç大æ·ã
ç¶èï¼ä»ä»¬çæ§è½å´å¤§ç¸åï¼æå¼å ¶ä»çå ç´ ï¼ä¾å¦ç½ç»ä¼ è¾æ¹å¼ï¼æ°æ®ç»æ设计ï¼æ件åå¨æ¹å¼ï¼æä»¬ä» ä» è®¨è®º Broker 端对æ件ç读åï¼ççä»ä»¬æä»ä¹ä¸åã
ä¸å¾æ¯æ¥¼ä¸»æ¥çæºç æ»ç»çå个 MQ 使ç¨çæ件读åæ¹å¼ã
é£ä¹ï¼å°åºæ¯ MMAP 强ï¼è¿æ¯ FileChannel 强ï¼
MMAP ä¼æå¨ç¥ï¼åºäº OS ç mmap çå åæ å°ææ¯ï¼éè¿ MMU æ å°æ件ï¼ä½¿éæºè¯»åæ件å读åå åç¸ä¼¼çé度ã
é£ FileChannel å¢ï¼æ¯é¶æ·è´åï¼å¾éæ¾ï¼ä¸æ¯ãFileChannel å¿«ï¼åªæ¯å 为ä»æ¯åºäº block çã
æ¥ä¸æ¥ï¼benchmark everything ââ å¾å¦.
å¦ä½ Benchmarkï¼ Benchmark åªäºï¼
æ¢ç¶æ¯è¯»åæ件ï¼èªç¶å°±è¦ç读åæ§è½ï¼è¿æ¯æåºæ¬çãä½ï¼æ³¨æï¼é常 MQ ä¼ä½¿ç¨å®æ¶å·çï¼é²æ¢æ°æ®ä¸¢å¤±ï¼MMAP å FileChannel é½æ force æ¹æ³ï¼ç¨äºå° pageCache çæ°æ®å·å°ç¡¬çä¸ãforce ä¼å½±åæ§è½åï¼ çæ¡æ¯ä¼ãå½±åå°ä»ä¹ç¨åº¦å¢ï¼ ä¸ç¥éãæ¯æ¬¡åå ¥çæ°æ®å¤§å°ä¼å½±åæ§è½åï¼æ¯«æ çé®ä¼ï¼ä½è§åæ¯ä»ä¹å¢ï¼FileOutputStream ççä¸æ æ¯å¤åï¼çæ¡æ¯ä¸ä¸å®ã
ä¸ç´ä»¥æ¥ï¼æ件è°ä¼é½æ¯èºæ¯ï¼å 为影åæ§è½çå ç´ å¤ªå¤ï¼é¦å ï¼SSD çåºç°ï¼å·²ç»è®©ä¼ ç»åºäº B+ tree çæ å½¢ç»æ产çäºèªæçé®ï¼ç¬¬äºï¼æ¯ä¸ªæ件系ç»çæ§è½ä¸åï¼Linux ext3 å ext4 æ§è½å¤©å£¤ä¹å«ï¼å é¤æ件çæ§è½å·®è·å¨ åå·¦å³ï¼ãè Max OS ç HFS+ ç³»ç»è¢« Linus 称ä¹ä¸ºâæå²ä»¥æ¥æåå¾çæ件系ç»âï¼å¹¸è¿çæ¯ï¼è¹æç»äºå¨ å¹´æ¨éäº macOS High Sierra å iOS .3 ç³»ç»ï¼è¿ä¸ªä¸¤ä¸ªç³»ç»é½æå¼äº HFS+ï¼æ¢æäºæ§è½æ´é«ç APFSãèæ¯ä¸ªæ件系ç»åå¯ä»¥è®¾ç½®ä¸åçè°åº¦ç®æ³ï¼å¦å¤ï¼è¿æèæå å缺页ä¸æ带æ¥çæ§è½æ¯åº.......
ï¼tipsï¼è¯å¿ç RocketMQ æä¾äº Linux IO è°ä¼çèæ¬ï¼è¿ç¹åçä¸é ï¼ï¼
è·é¢äºã
楼主åäºä¸ä¸ªå°é¡¹ç®ï¼ç¨äºæµè¯ Java MappedByteBuffer & FileChannel & RandomAccessFile & FileXXXputStream ç读åæ§è½ã大家ä¹å¯ä»¥å¨èªå·±çæºå¨ä¸è·è·çã
CPUï¼intel i7 4æ ¸8çº¿ç¨ 4.2GHz
å åï¼GB DDR4
ç£çï¼SSD 读å 2GB/s å·¦å³
JDK1.8
OSï¼Mac OS ..6
èæå åï¼ æªå ³éï¼å¤§å° 9GB
æµè¯æ³¨æç¹ï¼
1GB æ件ï¼
æµè¯ MappedByteBuffer & FileChannel & RandomAccessFile & FileInputStream.
ä»è¿å¼ å¾éï¼æ们çå°ï¼mmap æ§è½å®èï¼ç¹å«æ¯å¨å°æ°æ®éçæ åµä¸ãå ¶ä»çæµï¼åªæå¨4kb çæ åµä¸ï¼æå¼å§åæ mmapãå æ¤ï¼è¯» 4kb 以ä¸çæ°æ®ï¼è¯·ä½¿ç¨ mmapã
åæ¾å¤§çç mmap å FileChannel çæ¯è¾ï¼
æ ¹æ®ä¸å¾ï¼æ们çå°ï¼å¨åå ¥æ°æ®å å¤§äº 4kb 以ä¸çæ åµä¸ï¼FileChannel çä¸ä¼éé¶æ·è´ï¼åºæ¬å®è mmapï¼é¤äºé£ä¸ªä¸æ¬¡è¯» 1G æ件ç BT æµè¯ã
å æ¤ï¼å¦æä½ çæ°æ®å å¤§äº 4kbï¼è¯·ä½¿ç¨ FileChannelã
1GB æ件ï¼
æµè¯ MappedByteBuffer & FileChannel & RandomAccessFile & FileInputStream.
ä»ä¸å¾ï¼æ们å¯ä»¥çåºï¼mmap æ§è½è¿æ¯ä¸æ ·ç稳å®ãFileChannel ä¹ä¸å·®ï¼ä½æ¯å¨ åèæ°æ®éçæ åµä¸ï¼è¿å·®ç¹ææã
åç缩ç¥å¾ï¼
æ们çå°ï¼åè æ¯ FileChannel å mmap æ§è½çåæ°´å²ï¼ä» åèå¼å§ï¼FileChannel ä¸è·¯åæï¼ç´å° BT 1GB æ件ç¨ç¨è¾äºä¸ä¸¢ä¸¢ã
å æ¤ï¼æ们建议ï¼å¦æä½ çæ°æ®å 大å°å¨ åè以ä¸ï¼è¯·ä½¿ç¨ FileChannel åå ¥ã
æ们ç¥éï¼RocketMQ 使ç¨å¼æ¥å·çï¼é£ä¹å¼æ¥ force 对æ§è½æ没æå½±åå¢ï¼benchmark everythingãæ们使ç¨å¼æ¥çº¿ç¨ï¼æ¯ kb å·çä¸æ¬¡ï¼ççæ§è½å¦ä½ã
mmap ä¸ç´è½åï¼ä¸æ§è½å¾å·®ï¼é¤äºå¨ åèé£éæä¸ç¹ç¹æå¨ï¼åºæ¬ç»´æ å¨ å·¦å³ï¼è没æ force çæ åµä¸ï¼åå¨ å·¦å³ãè FileChannel åå®å ¨ä¸å force çå½±åãå¨æçæµè¯ä¸ï¼1GB çæ件ï¼ä¸æ¬¡ force éè¦ æ¯«ç§å·¦å³ãbuffer è¶å¤§ï¼æ¶é´è¶å¤ï¼åä¹åè¶å°ã
说个é¢å¤è¯ï¼Kafka ä¸ç´ä¸å»ºè®®ä½¿ç¨ forceï¼å¤§æ¦ä¹æè¿ä¸ªåå ãå½ç¶ï¼Kafka è¿æèªå·±çå¤å¯æ¬çç¥ä¿è¯æ°æ®å®å ¨ã
è¿éï¼æ们å¾åºç»è®ºï¼å¦æä½ éè¦ç»å¸¸æ§è¡ forceï¼å³ä½¿æ¯å¼æ¥çï¼ä¹è¯·ä¸å®ä¸è¦ä½¿ç¨ mmapï¼è¯·ä½¿ç¨ FileChannelã
åºäºä»¥ä¸æµè¯ï¼æ们å¾åºä¸å¼ å¾è¡¨ï¼
å设ï¼æ们çç³»ç»çæ°æ®å å¨ - å·¦å³ï¼æ们åºè¯¥ä½¿ç¨ä»ä¹çç¥ï¼
çï¼è¯»ä½¿ç¨ mmapï¼ä» ä» åä½¿ç¨ FileChannelã
ååè¿å¤´çç MQ çå®ç°è 们ï¼ä¼¼ä¹åªæ QMQ æ¯ è¿ä¹åçãå½ç¶ï¼RocketMQ ä¹æä¾äº FileChannel çåé项ãä½é»è®¤ mmap åå å¼æ¥å·çï¼åºè¯¥æ¯ broker busy çå å¶å§ã
è Kafkaï¼å 为é»è®¤ä¸ forceï¼ä¹æ¯ä½¿ç¨ FileChannel è¿è¡åå ¥çï¼ä¸ºä»ä¹ä½¿ç¨ FileChannel 读å¢ï¼å¤§æ¦æ¯å 为æ¶æ¯ç大å°å¨ 4kb 以ä¸å§ã
è¿æ ·ä¸æ£æµï¼è¿äº MQ ç设计似ä¹é½é常åçã
æåï¼è½ä¸ç¨ force å°±å«ç¨ forceãå¦æè¦ç¨ force ï¼å°±è¯·ä½¿ç¨ FileChannelã
èè微信 Xlog
åæ¥å°å
æ¬æä»ç» MARS xlog 使ç¨ä»¥å使ç¨è¿ç¨ä¸è¸©è¿çå
xlog æ¯å¾®ä¿¡å¼æºæ¡æ¶ MARS çä¸é¨å,源码 å¤çåºç¨æ¥å¿
微信ç对 xlog çä»ç»ææ¡£--ã 微信ç»ç«¯è·¨å¹³å°ç»ä»¶ mars ç³»åï¼ä¸ï¼ - é«æ§è½æ¥å¿æ¨¡åxlog) ã
æ»ç»åºæ¥å°±æ¯
MARS ç GitHub ä¸ä»ç»æ¯è¾è¯¦ç»,
å è·èµ·æ¥ä¸ä¸ª Demo ä¹å, éè¦æ·±å ¥äºè§£ä¸ä¸
mmap æ¯ä¸ç§å åæ å°æ件çæ¹æ³ï¼å³å°ä¸ä¸ªæ件æè å ¶å®å¯¹è±¡æ å°å°è¿ç¨çå°å空é´ï¼å®ç°æ件ç£çå°ååè¿ç¨èæå°å空é´ä¸ä¸æ®µèæå°åçä¸ä¸å¯¹æ å ³ç³»ãå®ç°è¿æ ·çæ å°å ³ç³»åï¼è¿ç¨å°±å¯ä»¥éç¨æéçæ¹å¼è¯»åæä½è¿ä¸æ®µå åï¼èç³»ç»ä¼èªå¨ååè页é¢å°å¯¹åºçæ件ç£çä¸ï¼å³å®æäºå¯¹æ件çæä½èä¸å¿ åè°ç¨read,writeçç³»ç»è°ç¨å½æ°ãç¸åï¼å æ ¸ç©ºé´å¯¹è¿æ®µåºåçä¿®æ¹ä¹ç´æ¥åæ ç¨æ·ç©ºé´ï¼ä»èå¯ä»¥å®ç°ä¸åè¿ç¨é´çæä»¶å ±äº«ã
æ£å¦å¾®ä¿¡çä»ç»æç« ä¸æ说ç:
mmap æ¯ä½¿ç¨é»è¾å å对ç£çæ件è¿è¡æ å°ï¼ä¸é´åªæ¯è¿è¡æ å°æ²¡æä»»ä½æ·è´æä½ï¼é¿å äºåæ件çæ°æ®æ·è´ãæä½å åå°±ç¸å½äºå¨æä½æ件ï¼é¿å äºå æ ¸ç©ºé´åç¨æ·ç©ºé´çé¢ç¹åæ¢ã
mmapå ä¹åç´æ¥åå åä¸æ ·çæ§è½ï¼èä¸ mmap æ¢ä¸ä¼ä¸¢æ¥å¿ï¼ååæ¶æºå¯¹æ们æ¥è¯´ååºæ¬å¯æ§ã
ä¸æä¸æå ³äºè¯¥æ¹æ³çæºç åæ, æ»ç»æ¥è¯´
å 为 Android ææº CPU æ¶æçå·®å¼, å¯è½ä¼æå¾å¤çæ¬ç so æ件, å¦æä½ æ¯ä½¿ç¨æ¬å°ç¼è¯ xlog ç, ä½ åºè¯¥æ³¨æ对åºä¸å CPU æ¶æç¼è¯ä¸åç so æ件
æ¬å°ç¼è¯ç so æ件æ¾å¨ src/jniLibs ç®å½ä¸, AS å¯ä»¥èªå¨ç¼è¯å° apk ä¸
æçå主è¦æ¯å 为 xposed çåå , åå¼å§ Demo å¾é¡ºå©, æ¥å ¥å°é¡¹ç®ä¸é®é¢å°±ä¸ä¸ªä¸ªç
ä¸æ以åæå°ä¼å¨åªéå è½½ so æ件, ä½æ¯ç±äº xposed çåå , Classloader æåçæ件为 /data/app/io.communet.ichater-2/base.apk , ä¸è½æ¾å°æå®ç so æ件, æ以éè¦æå®ç»å¯¹è·¯å¾
解å³:
微信ææå°å ³äºæ¥å¿åæ¥åå¼æ¥ä¸¤ç§åå ¥æ¹å¼ä»¥åæ¥å¿æ件çåå¨ä½ç½®
å®é è¿è¡ä¸åç°, å½åæ¥åå ¥æ¶, æ¥å¿æ件å¼å§ä¼è¢«åæ¾å¨ cacheDir, ä¸æ®µæ¶é´å, ä¼è¢«æ¾å° logDir, ä½æ¯å¼æ¥æ¨¡å¼ä¸, æ件ä¸ç´æ¾å¨ cacheDir, å³ä¾¿è°ç¨ appenderFlush æ¹æ³, æ¥å¿ä¼ä» mmap ä¸åå ¥æ件, ä½æ¯æ件çä½ç½®è¿æ¯å¨ cacheDir, å½ç¶, åºç¨æ读å SDCard çæé
解å³:
该é®é¢è¿æªæ¥æåå , ç®åç解å³æ¹æ³æ¯ä¸ç» cacheDir, æ件ä¼è¢«ç´æ¥æ¾å° logDir, ä½æ¯, å®æ¹è¯´å¦æä¸ç» cacheDir, å¯è½åºç° SIGBUS, åè§ issue#
/4/æ´æ°: 解å³äº, 说起æ¥é½ææ§, è¿æä¸ä¸ªåæ°
å°è¯¥å¼è®¾ç½®ä¸º 0 å³å¯, ä¹å以为è¿ä¸ªå¼è¡¨ç¤ºçæ¯ç¼åæ¥å¿ä¿åç天æ°, è®¾ç½®äº 7, å®é ä¸ä¿çç¼åæ¥å¿ç天æ°é»è®¤ 天, æ¸ çé»è¾å¦ä¸
注æåä¸æä¸çé£ä¸ª BUG åºå, è¿éæ¯å ä¸ºç¨ ä½ç so ä»£æ¿ ä½ç so 导è´ç
解å³:
jniLibs ä¸é¢ä¸è¦æ¾ ä½ç, åªæ¾ ç, å¯ä»¥å ¼å®¹
è¿æåçè¯ç»§ç»æ´æ°
C++/C 内存分配-malloc/mmap/syscall深度解析以及性能测试
用于实现动态内存分配函数(如malloc、free等)以及操作系统级的分析内存管理。
通常情况下,源码malloc和free会使用brk或sbrk来动态管理进程的分析堆空间。它们会请求增加或减少堆空间的源码大小,以满足动态内存分配的分析vscode 看源码需求。
在理解brk和sbrk时,源码需要考虑以下几点:
上面这些都是分析理论知识,和实际还有不小的源码差距,大家不要直接记这些理论,分析一定要动手自己实践,源码看到什么样的分析结果,就是源码什么样,看不到的分析就后面有机会再补充。
(文章内涉及的源码源码截图或者片段,若您需要源码工程,可以关注后留言找我要。 )
首先在大多数系统中,栈是有固定大小的,当程序启动时系统会为栈分配一块固定大小的内存空间。栈的大小受限于系统的限制,当栈空间用尽时会引发栈溢出(stack overflow)错误。所以栈不存动态增长的可能,所以我们暂时只分析堆的内存分配。
注意这个KB,说的是每次沈内存的时候判断,不是说累计情况,比如你每次申请1KB,申请了多次,那肯定超了,此时还是会继续使用brk分配,并不会使用mmap。 只有你一次性申请超过KB是才会调用mmap
场景:申请5次内存,前3次申请小内存,后面2次申请超过KB,看看linux系统分配的内存是怎样的?
代码路径:\usr\cbasics_demo\1_malloc_Demo\4_malloc_demo.cpp
sbrk(0)会返回当前brk指针的位置。具体来说,它返回当前数据段的结束地址,也就是堆的顶端。当你调用sbrk(0)时,它实际上并不会改变brk指针的位置,只是返回当前brk指针的值。
可以看到上面的ptr1到ptr3内存地址很接近,说明是连续的,因为我写的代码申请的都是小内存,只有几个字母。爬虫源码是
而从ptr4开始,内存地址完全变了,你可以理解pt3的分布还在秦皇岛,而pt4和pt5直接给你放北京了。
他们的区别就在于大小,pt4和pt5是超过KB的,由此可以证明这块的内存分配肯定是不同的。
而继续看Current brk的打印,这里打印的是当前进程内的内存地址:0xc 这很明显和pt1,pt2,pt3 都是在一块区域的,我觉得这足以证明 这三个是用的brk进行分配,而pt4和5没有用brk,因为brk的最新指针地址没有包含他俩。他俩的地址,早就超出了brk的指针范围。
继续看释放哪里的打印,我分别释放了pt1一直到pt5,但是brk的指针地址,一点没变,还是0xc 说明,在底层free函数,不会立即释放内存,brk指针地址并没有改变。 下次申请内存时肯定会重复使用,所以它的性能比较高。
我基于这个demo画了个内存图,方便理解:
malloc函数,会调用brk和mmap(也就相当于syscall),所以性能测试只需触发malloc的小块内存和大块内存分配即可。测试场景如下:
(1)暴力基础测试,不考虑场景,直接测试申请内存效率
(2)触发malloc函数,持续申请小块内存,比如一个list集合或者数组数据,每个内容很小,但是加在一起很大,这时候我们是直接申请一大块内存,还是递增的申请小块内存呢?
(3)触发malloc函数的,大块内存申请,就是内存映射mmap,如果我创建的对象每个都很大,比如里面存储的是业务数据,一个对象就几百兆,那我是直接申请一大块内存做内存映射?还是将该对象拆分掉小块,去申请一堆小块内存呢?
使用malloc申请1万次小块内存,每个内存只有sizeof(char)大小。xp源码备份再使用mmap申请1万次内存,每次申请
*小块内存:0. 秒 大块内存:0. 秒 相差了了倍。
修改限制,不在使用次数,而是固定大小,申请小块内存最大只申请MB,但是需要申请很多次,因为每次只是申请*sizeof(char)。
而大块内存每次申请:2** 但是最大申请MB。
结果:
小块:0. 秒 大块:0.秒 相差了倍
总结:从上面的实验得知,申请大块内存和申请小块内存在性能上并没有太大的区别,根本原因是申请次数,你申请大块内存是为了减少申请次数,并不是申请大块内存就快。同样的小块内存申请也一样,你申请的小,也不能频繁的申请,比如第二个场景,为了MB的空间,小块内存申请了万次,结果性能比申请大块内存相差了倍。
重点是:频率
对于内存分配的性能,通常需要考虑以下几个方面:
尝试分析小块内存申请情况
代码如下:
运行结果如下:
第一次打印的结果:
第二次打印的结果:
根据这些数据,我们可以初步分析内存碎片的情况:
malloc和free是C语言库函数,而在C++中常用的是new和delete,
C里面是用malloc_stats();
而C++则需要用/proc/self/smaps文件来查看进程的内存映射情况 ,但是大块内存无法用这个查看,比如mmap分配的。需要其他内存分析工具
A:他们直接的区别
new和delete是C++中的运算符,而malloc和free是C语言中的函数。它们之间有几个重要的区别:
总的来说,new和delete更适合在C++中使用,因为它们提供了更好的类型安全性、异常处理和对象构造/析构的支持。而在C语言中,或者需要与C代码进行交互时,可以使用malloc和free。
B:单纯性能的对比
从性能和原理的角度来看,new和delete与malloc和free之间也存在一些区别:
总的来说,从性能和原理的角度来看,new和delete在处理类对象和支持面向对象编程方面更加方便和安全,而malloc和free则更适合于处理简单的内存分配和释放操作。
然而在C++中,operator new通常会调用malloc来分配内存,但它并不是直接调用malloc函数。相反,咸宁家装网源码C++标准库会提供operator new的重载版本,以便用户可以自定义内存分配行为。这意味着operator new可以使用不同的内存分配策略,而不仅仅是调用malloc。
因此,尽管new操作符在底层可能会使用operator new来执行内存分配,而operator new可能会使用malloc来分配内存,但new操作符并不会直接调用malloc函数。这种分层的设计使得C++的内存分配更加灵活,并且允许用户自定义内存分配策略。
最后这个总结我没法证明,毕竟还没看new的源码,现在查询到的资料看底层最终还是会到c的malloc函数上。
编译:g++ -o 5_2_pmTest_malloc_demo.o 5_2_pmTest_malloc_demo.cpp -lrt
运行: ./5_2_pmTest_malloc_demo.o
运行结果:可以看到C++并没有多太多。
C malloc and free time: 0. seconds
C++ new and delete time: 0. seconds
零拷贝技术及在Java中应用
零拷贝技术及在Java中的应用
前言
本文旨在探讨零拷贝技术在Java领域中的应用,通过对几个知名开源软件的源码分析,以揭示其背后的优化机制。零拷贝技术的核心在于减少数据在用户空间与内核空间之间不必要的复制,从而提升性能。
什么是零拷贝
零拷贝技术是指在数据传输过程中,无需CPU参与数据从一个内存区域复制到另一个内存区域的过程,以减少系统开销。
OS层传统I/O
在Linux环境下,传统I/O操作涉及到数据从用户空间到内核空间,以及从内核空间到磁盘或网络设备的复制,通常需要两次系统调用,产生四次上下文切换。
零拷贝技术mmap
通过mmap系统调用,Linux将内核空间与用户空间的虚拟地址映射到同一物理地址,实现数据在内核空间中的直接操作,从而减少CPU和内存之间的数据复制。mmap结合write操作能显著提升I/O速度,同时减少上下文切换。
sendfile
sendfile是Linux内核提供的另一个系统调用,允许在文件描述符之间传输数据,避免了内核缓冲区与用户缓冲区之间的数据复制,进一步实现了零拷贝。其流程包括三次数据拷贝,其中两次是DMA拷贝。
sendfile+DMA scatter/gather
通过在内核空间和socket buffer之间记录内存地址和偏移量,sendfile操作可以进一步减少CPU拷贝,实现更高效的零拷贝。scatter/gather方法减少了数据在内核空间和socket之间的拷贝,但硬件及驱动程序的支持是关键。
splice
splice调用引入于Linux 2.6.版本,期货指标 源码具备了sendfile的所有功能,并且提供了更广泛的用例。它能够替代sendfile机制,实现更灵活的数据传输。
小结
零拷贝技术通过减少CPU拷贝和上下文切换,显著提升了数据传输效率。尽管两次DMA拷贝仍难以避免,但这些技术在不同层面上优化了数据传输过程。
Java层零拷贝技术
考虑到JVM的垃圾回收机制,Java的零拷贝技术主要关注如何利用堆外内存减少内存的移动。DirectByteBuffer提供了直接与操作系统内存交互的接口,避免了JVM堆内存与OS用户堆之间的数据拷贝。
Netty与零拷贝
Netty通过优化数据传输流程,实现了高效的零拷贝技术,减少了不必要的数据拷贝,从而提升整体性能。
开源分析Tomcat
Tomcat通过利用零拷贝技术,如sendfile,来优化静态资源的传输,避免不必要的数据压缩过程,以提升性能和带宽利用率。
RocketMQ与零拷贝
RocketMQ通过使用mmap技术实现高效的CommitLog文件传输,减少了JVM堆内存的拷贝,从而提高了消息处理速度。
结语
本文综述了零拷贝技术的原理及其在Java领域中的应用,通过分析开源软件的源码,展示了零拷贝技术的实践与优势。希望本文能为读者提供启发,引导在实际开发中更有效地利用零拷贝技术,提升系统性能。
Linux内核虚拟内存管理之匿名映射缺页异常分析
让我们深入探讨Linux内核中的匿名映射缺页异常,这个现象在内存管理中至关重要。本文基于linux-5.0内核源代码进行讲解,内容分为几个部分。
首先,理解什么是匿名页至关重要。匿名页与文件页相对,它们不对应任何文件,比如进程的堆和栈。当程序使用malloc或mmap分配内存时,即使虚拟内存已分配,物理内存可能尚未分配,首次访问时会触发缺页异常来为虚拟内存分配物理空间。
接着,我们聚焦于0页的概念。在系统初始化时,会预先分配一页全为0的内存,称为0页。0页的使用在于节省内存,匿名页第一次读取时,如果数据是0,会映射到0页,写操作时则会触发页面复制。
当匿名映射缺页异常发生时,处理器会触发一系列处理流程。在源代码中,handle_pte_fault函数会检查页表项是否缺失和是否为匿名映射,然后调用do_anonymous_page处理。这个函数会根据操作(读写)判断是否使用0页,并根据权限设置页表属性。
在第一次读写匿名页时,内核代码会进行详细处理,例如在mmap映射内存时,会检查并设置页的可读写属性。如果是写操作,即使之前设置了写权限,页表项在第一次写入时也会变为只读,直到下次写操作时才会分配新物理页。
最后,通过实验验证了内核按需分配页的策略,映射和写操作前后内存使用情况的变化证实了匿名页的动态分配特性。总结来说,匿名映射缺页异常是内存管理中的关键点,理解它能帮助我们更好地优化程序性能和内存利用。
Linux内核黑科技——mmap实现详解
本文旨在详细阐述 Linux 内核中的 mmap 实现机制。mmap 的全称是 memory map,即内存映射,其功能是将文件内容映射到内存中,允许我们直接对映射的内存区域进行读写操作,效果等同于直接对文件进行读写。 mmap 实现分为两个关键步骤:文件映射和缺页异常处理。首先,使用 mmap() 系统调用时,内核会通过 do_mmap_pgoff() 函数进行处理,这一过程主要是为进程分配虚拟内存空间,并初始化相关数据结构。文件映射则通过 mmmap_region() 函数完成,该函数负责在 vm_area_struct 结构中登记文件信息,以便后续的内存访问操作。 在文件映射阶段,虚拟内存地址会映射到文件的页缓存中。当进程试图访问映射后的虚拟内存地址时,若该地址对应的内容未被加载到物理内存中,则会导致缺页异常。这就是我们接下来要介绍的第二步:缺页异常处理。 当 CPU 触发缺页异常时,内核会调用 do_page_fault() 函数来处理这一异常情况。在这一过程中,文件的页缓存内容会被加载到物理内存中,与虚拟内存地址建立起映射关系。这一机制确保了当进程访问文件内容时,可以无缝地在物理内存和文件之间进行数据交换,从而实现高效的文件读写操作。 综上所述,mmap 通过将文件内容映射到虚拟内存中,允许我们直接对映射区域进行读写操作,而背后的关键在于文件的页缓存与虚拟内存地址之间的动态映射。这一机制是 Linux 内核实现高效文件访问和管理的重要技术之一。 对于需要深入学习 Linux 内核源码、内存调优、文件系统、进程管理、设备驱动、网络协议栈等领域的开发者,推荐加入 Linux 内核源码交流群:,群内提供丰富的学习资源,包括精选书籍、视频资料等,以及价值的内核资料包,包含视频教程、电子书、实战项目及代码。前名加入者还将获得额外赠送的资料。 此外,我们整理了以下精选文章,供对 Linux 内核感兴趣的读者参考:浅谈 ARM Linux 内核页表的块映射
内核大神教你从 Linux 进程的角度看 Docker
Linux 下 CAN 总线是如何使用的?
谈谈 Linux 内存管理的前世今生
深入分析 Linux socket 数据发送过程
盘点那些 Linux 内核调试手段——内核打印
Linux 环境下网络分析和抓包是怎么操作的?
fs/dev/zero的实现
在类UNIX操作系统中,/dev/zero是一个特殊文件,提供无限空字符流。常用于覆盖信息或生成特定大小空白文件。其实现依赖于mmap将/dev/zero映射至虚地址空间,实现共享内存。该操作等同于匿名内存使用,即没有与任何文件关联。系统分配内容(通过mmap或brk)通常清零,但虚拟地址按需分配物理页面。读取操作仅需保证零内容,虚拟地址映射至内容为0的物理页面,降低系统物理内存消耗。
在Linux中,万物皆是文件,/dev/zero的实现涉及特定目录下的tmpfs文件系统。通过shmem_zero_setup、shmem_kernel_file_setup和alloc_file等步骤构建。
mmap共享匿名映射实质上是文件映射,特殊文件位于/dev/zero目录,创建于tmpfs系统中。
相关文献深入剖析了mmap原理、共享内存虚拟文件系统、mmap内存映射本质及其源码实现。
进一步理解Linux内核共享内存机制,包括shmem和tmpfs,提供深入分析。
面试 | 再也不怕被问 Binder 机制了
Binder机制是Android特有的进程间通信(IPC)方式,它基于C/S架构,由运行在用户空间的Client、Server、Service Manager组件,以及运行在内核空间的Binder驱动组成。完整过程包括:通过内存映射技术减少数据拷贝次数,发送方进程也做内存映射可以实现数据0拷贝传输,但考虑到性能和复杂性,Binder方式更适合Android。
mmap内存映射原理是在进程的用户空间和内核空间之间建立映射关系,实现文件磁盘地址与进程虚拟地址空间中的虚拟地址一一对映,使得进程可以采用指针方式读写操作内存,系统自动回写脏页面到磁盘,完成文件操作而无需再调用read、write等系统调用函数。同时,内核空间对这段区域的修改直接反映用户空间,实现不同进程间的文件共享。
在进程间通信(IPC)场景下使用mmap时,通常只需要在进程的用户空间和内核空间之间建立映射关系,不一定需要映射到外部存储介质,除非希望将共享内存内容持久化到磁盘上。
当使用匿名内存映射进行进程间通信时,创建一段内核空间内存并在进程的用户空间与之建立映射关系,允许多个进程共享同一段内核空间内存,实现数据共享和同步。匿名内存映射不与任何文件关联,仅在进程间实现高效数据传输。
在使用mmap进行进程间通信时,创建匿名内存映射,不映射到外部存储介质,仅在用户空间与内核空间之间建立映射关系。这允许多个进程共享内核空间内存,提高数据访问效率和性能。
在实际应用中,使用带有回调接口(Callback)的方法参数调用服务端进程提供的方法时,方法调用线程和回调线程是否相同取决于服务端实现。通常服务端采用异步处理方式,将请求放入队列或线程池中处理,调用回调接口,线程可能不相同。
对于oneway接口调用,即使服务端立即在当前线程中处理请求并调用回调接口,客户端的调用也不会阻塞。oneway调用是单向异步的,客户端调用后立即返回,不会等待服务端响应。
Intent传递参数在同一个进程中的两个Activity间,由于涉及Binder IPC通信,Intent数据携带大小会受到Binder事务大小限制。通常限制在1MB左右,超过限制会抛出异常。解决方法包括优化数据结构、使用事件总线或回调接口传递大对象。
为了深入理解Android框架,可参考《Android Framework核心知识点》手册,内容涵盖Init、Zygote、SystemServer、Binder、Handler、AMS、PMS、Launcher等知识点,以及相关源码分析资料,帮助快速掌握Android框架核心。
Linux USB 驱动开发实例(一)——USB摄像头驱动实现源码分析
Linux下的USB摄像头驱动实现源码分析,主要通过四个部分完成:设备模块的初始化与卸载、上层软件接口模块、数据传输模块以及USB CORE的支持。
一、初始化设备模块
模块初始化和卸载通过调用`module_init`和`module_exit`函数实现,关键数据结构为USB驱动结构,支持即插即用功能,通过`spca5xx_probe`和`spca5xx_disconnect`函数。
二、上层软件接口模块
基于V4L协议规范,通过`file_operations`数据结构实现设备关键系统调用,功能包括:Open打开初始化、Close关闭、Read读取数据、Mmap内存映射、Ioctl获取文件信息等。Open功能初始化解码器模块,Read功能主要将数据从内核空间传至进程用户空间。
三、数据传输模块
采用tasklet实现同步快速数据传递,通过软件解码模块在`spcadecode.c`上解压缩图形数据流,如yyuyv、yuvy、jpeg、jpeg至RGB格式。解码算法依赖于硬件压缩算法,最终需DSP芯片实现。
四、USB CORE的支持
使用系统实现的USB CORE层提供函数接口,如`usb_control_msg`、`usb_sndctrlpipe`等,实现对USB端点寄存器的读写操作。
总结,本Linux USB摄像头驱动源码分析覆盖了驱动的初始化、上层接口实现、数据传输及USB CORE支持,涉及C/C++、Linux、Nginx等技术点。学习资料包括视频教程、技术路线图、文档等,通过私信获取。课程包含C/C++、Linux、Nginx等后端服务器架构开发技术,为学习者提供全面指导。