﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-T9的空间 </title><link>http://www.cppblog.com/xieshuo/</link><description>You will never walk alone!</description><language>zh-cn</language><lastBuildDate>Wed, 08 Apr 2026 06:22:58 GMT</lastBuildDate><pubDate>Wed, 08 Apr 2026 06:22:58 GMT</pubDate><ttl>60</ttl><item><title>算法导论读书笔记.</title><link>http://www.cppblog.com/xieshuo/archive/2014/07/08/207577.html</link><dc:creator> Torres</dc:creator><author> Torres</author><pubDate>Tue, 08 Jul 2014 12:11:00 GMT</pubDate><guid>http://www.cppblog.com/xieshuo/archive/2014/07/08/207577.html</guid><wfw:comment>http://www.cppblog.com/xieshuo/comments/207577.html</wfw:comment><comments>http://www.cppblog.com/xieshuo/archive/2014/07/08/207577.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/xieshuo/comments/commentRss/207577.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/xieshuo/services/trackbacks/207577.html</trackback:ping><description><![CDATA[许下一个美好愿望吧，期望能在空余的时间把多年前买的一本书看完。<br />Pushing yourself when no one else is around.<img src ="http://www.cppblog.com/xieshuo/aggbug/207577.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/xieshuo/" target="_blank"> Torres</a> 2014-07-08 20:11 <a href="http://www.cppblog.com/xieshuo/archive/2014/07/08/207577.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Linux memory summary</title><link>http://www.cppblog.com/xieshuo/archive/2013/12/09/204679.html</link><dc:creator> Torres</dc:creator><author> Torres</author><pubDate>Mon, 09 Dec 2013 09:42:00 GMT</pubDate><guid>http://www.cppblog.com/xieshuo/archive/2013/12/09/204679.html</guid><wfw:comment>http://www.cppblog.com/xieshuo/comments/204679.html</wfw:comment><comments>http://www.cppblog.com/xieshuo/archive/2013/12/09/204679.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/xieshuo/comments/commentRss/204679.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/xieshuo/services/trackbacks/204679.html</trackback:ping><description><![CDATA[<span style="font-size: 10.5pt; font-family: Verdana, sans-serif;">From Unix某论坛，忘记名字了...但这段文字从宏观上讲清楚了Linux Memory的构架。<br />1. </span><span style="font-size: 10.5pt; font-family: 宋体;">内核初始化：</span><span style="font-size: 10.5pt; font-family: Verdana, sans-serif;"><br /> <br /> &nbsp; &nbsp; * </span><span style="font-size: 10.5pt; font-family: 宋体;">内核建立好内核页目录页表数据库，假设物理内存大小为</span><span style="font-size: 10.5pt; font-family: Verdana, sans-serif;">len</span><span style="font-size: 10.5pt; font-family: 宋体;">，则建立了</span><span style="font-size: 10.5pt; font-family: Verdana, sans-serif;">[3G--3G+len]::[0--len]</span><span style="font-size: 10.5pt; font-family: 宋体;">这样的虚地址</span><span style="font-size: 10.5pt; font-family: Verdana, sans-serif;">vaddr</span><span style="font-size: 10.5pt; font-family: 宋体;">和物理地址</span><span style="font-size: 10.5pt; font-family: Verdana, sans-serif;">paddr</span><span style="font-size: 10.5pt; font-family: 宋体;">的线性对应关系；</span><span style="font-size: 10.5pt; font-family: Verdana, sans-serif;"><br /> &nbsp; &nbsp; * </span><span style="font-size: 10.5pt; font-family: 宋体;">内核建立一个</span><span style="font-size: 10.5pt; font-family: Verdana, sans-serif;">page</span><span style="font-size: 10.5pt; font-family: 宋体;">数组，</span><span style="font-size: 10.5pt; font-family: Verdana, sans-serif;">page</span><span style="font-size: 10.5pt; font-family: 宋体;">数组和物理页面系列完全是线性对应，</span><span style="font-size: 10.5pt; font-family: Verdana, sans-serif;">page</span><span style="font-size: 10.5pt; font-family: 宋体;">用来管理该物理页面状态，每个物理页面的虚地址保存在</span><span style="font-size: 10.5pt; font-family: Verdana, sans-serif;">page-&gt;virtual</span><span style="font-size: 10.5pt; font-family: 宋体;">中；</span><span style="font-size: 10.5pt; font-family: Verdana, sans-serif;"><br /> &nbsp; &nbsp; * </span><span style="font-size: 10.5pt; font-family: 宋体;">内核建立好一个</span><span style="font-size: 10.5pt; font-family: Verdana, sans-serif;">free_list</span><span style="font-size: 10.5pt; font-family: 宋体;">，将没有使用的物理页面对应的</span><span style="font-size: 10.5pt; font-family: Verdana, sans-serif;">page</span><span style="font-size: 10.5pt; font-family: 宋体;">放入其中，已经使用的就不用放入了；</span><span style="font-size: 10.5pt; font-family: Verdana, sans-serif;"><br /> <br /> 2. </span><span style="font-size: 10.5pt; font-family: 宋体;">内核模块申请内存</span><span style="font-size: 10.5pt; font-family: Verdana, sans-serif;">vaddr = get_free_pages(mask,order)</span><span style="font-size: 10.5pt; font-family: 宋体;">：</span><span style="font-size: 10.5pt; font-family: Verdana, sans-serif;"><br /> <br /> &nbsp; &nbsp; * </span><span style="font-size: 10.5pt; font-family: 宋体;">内存管理模块从</span><span style="font-size: 10.5pt; font-family: Verdana, sans-serif;">free_list</span><span style="font-size: 10.5pt; font-family: 宋体;">找到一个</span><span style="font-size: 10.5pt; font-family: Verdana, sans-serif;">page</span><span style="font-size: 10.5pt; font-family: 宋体;">，将</span><span style="font-size: 10.5pt; font-family: Verdana, sans-serif;">page-&gt;virtual</span><span style="font-size: 10.5pt; font-family: 宋体;">作为返回值，该返回值就是对应物理页面的虚地址；</span><span style="font-size: 10.5pt; font-family: Verdana, sans-serif;"><br /> &nbsp; &nbsp; * </span><span style="font-size: 10.5pt; font-family: 宋体;">将</span><span style="font-size: 10.5pt; font-family: Verdana, sans-serif;">page</span><span style="font-size: 10.5pt; font-family: 宋体;">从</span><span style="font-size: 10.5pt; font-family: Verdana, sans-serif;">free_list</span><span style="font-size: 10.5pt; font-family: 宋体;">中脱离；</span><span style="font-size: 10.5pt; font-family: Verdana, sans-serif;"><br /> &nbsp; &nbsp; * </span><span style="font-size: 10.5pt; font-family: 宋体;">模块使用该虚拟地址操作对应的物理内存；</span><span style="font-size: 10.5pt; font-family: Verdana, sans-serif;"><br /> <br /> 3. </span><span style="font-size: 10.5pt; font-family: 宋体;">内核模块使用</span><span style="font-size: 10.5pt; font-family: Verdana, sans-serif;">vaddr</span><span style="font-size: 10.5pt; font-family: 宋体;">，例如执行指令</span><span style="font-size: 10.5pt; font-family: Verdana, sans-serif;">mov(eax, vaddr)</span><span style="font-size: 10.5pt; font-family: 宋体;">：</span><span style="font-size: 10.5pt; font-family: Verdana, sans-serif;"><br /> <br /> &nbsp; &nbsp; * CPU</span><span style="font-size: 10.5pt; font-family: 宋体;">获得</span><span style="font-size: 10.5pt; font-family: Verdana, sans-serif;">vaddr</span><span style="font-size: 10.5pt; font-family: 宋体;">这个虚地址，利用建立好的页目录页表数据库，找到其对应的物理内存地址；</span><span style="font-size: 10.5pt; font-family: Verdana, sans-serif;"><br /> &nbsp; &nbsp; * </span><span style="font-size: 10.5pt; font-family: 宋体;">将</span><span style="font-size: 10.5pt; font-family: Verdana, sans-serif;">eax</span><span style="font-size: 10.5pt; font-family: 宋体;">的内容写入</span><span style="font-size: 10.5pt; font-family: Verdana, sans-serif;">vaddr</span><span style="font-size: 10.5pt; font-family: 宋体;">对应的物理内存地址内；</span><span style="font-size: 10.5pt; font-family: Verdana, sans-serif;"><br /> <br /> 4. </span><span style="font-size: 10.5pt; font-family: 宋体;">内核模块释放内存</span><span style="font-size: 10.5pt; font-family: Verdana, sans-serif;">free_pages(vaddr,order)</span><span style="font-size: 10.5pt; font-family: 宋体;">：</span><span style="font-size: 10.5pt; font-family: Verdana, sans-serif;"><br /> <br /> &nbsp; &nbsp; * </span><span style="font-size: 10.5pt; font-family: 宋体;">依据</span><span style="font-size: 10.5pt; font-family: Verdana, sans-serif;">vaddr</span><span style="font-size: 10.5pt; font-family: 宋体;">找到对应的</span><span style="font-size: 10.5pt; font-family: Verdana, sans-serif;">page</span><span style="font-size: 10.5pt; font-family: 宋体;">；</span><span style="font-size: 10.5pt; font-family: Verdana, sans-serif;"><br /> &nbsp; &nbsp; * </span><span style="font-size: 10.5pt; font-family: 宋体;">将该</span><span style="font-size: 10.5pt; font-family: Verdana, sans-serif;">page</span><span style="font-size: 10.5pt; font-family: 宋体;">加入到</span><span style="font-size: 10.5pt; font-family: Verdana, sans-serif;">free_list</span><span style="font-size: 10.5pt; font-family: 宋体;">中；</span><span style="font-size: 10.5pt; font-family: Verdana, sans-serif;"><br /> <br /> 5. </span><span style="font-size: 10.5pt; font-family: 宋体;">用户进程申请内存</span><span style="font-size: 10.5pt; font-family: Verdana, sans-serif;">vaddr = malloc(size)</span><span style="font-size: 10.5pt; font-family: 宋体;">：</span><span style="font-size: 10.5pt; font-family: Verdana, sans-serif;"><br /> <br /> &nbsp; &nbsp; * </span><span style="font-size: 10.5pt; font-family: 宋体;">内存管理模块从用户进程内存空间</span><span style="font-size: 10.5pt; font-family: Verdana, sans-serif;">(0--3G)</span><span style="font-size: 10.5pt; font-family: 宋体;">中找到一块还没使用的空间</span><span style="font-size: 10.5pt; font-family: Verdana, sans-serif;">vm_area_struct(start--end)</span><span style="font-size: 10.5pt; font-family: 宋体;">；</span><span style="font-size: 10.5pt; font-family: Verdana, sans-serif;"><br /> &nbsp; &nbsp; * </span><span style="font-size: 10.5pt; font-family: 宋体;">随后将其插入到</span><span style="font-size: 10.5pt; font-family: Verdana, sans-serif;">task-&gt;mm-&gt;mmap</span><span style="font-size: 10.5pt; font-family: 宋体;">链表中；</span><span style="font-size: 10.5pt; font-family: Verdana, sans-serif;"><br /> <br /> 6. </span><span style="font-size: 10.5pt; font-family: 宋体;">用户进程写入</span><span style="font-size: 10.5pt; font-family: Verdana, sans-serif;">vaddr(0-3G)</span><span style="font-size: 10.5pt; font-family: 宋体;">，例如执行指令</span><span style="font-size: 10.5pt; font-family: Verdana, sans-serif;">mov(eax, vaddr)</span><span style="font-size: 10.5pt; font-family: 宋体;">：</span><span style="font-size: 10.5pt; font-family: Verdana, sans-serif;"><br /> <br /> &nbsp; &nbsp; * CPU</span><span style="font-size: 10.5pt; font-family: 宋体;">获得</span><span style="font-size: 10.5pt; font-family: Verdana, sans-serif;">vaddr</span><span style="font-size: 10.5pt; font-family: 宋体;">这个虚地址，该虚地址应该已经由</span><span style="font-size: 10.5pt; font-family: Verdana, sans-serif;">glibc</span><span style="font-size: 10.5pt; font-family: 宋体;">库设置好了，一定在</span><span style="font-size: 10.5pt; font-family: Verdana, sans-serif;">3G</span><span style="font-size: 10.5pt; font-family: 宋体;">一下的某个区域，根据</span><span style="font-size: 10.5pt; font-family: Verdana, sans-serif;">CR3</span><span style="font-size: 10.5pt; font-family: 宋体;">寄存器指向的</span><span style="font-size: 10.5pt; font-family: Verdana, sans-serif;">current-&gt;pgd</span><span style="font-size: 10.5pt; font-family: 宋体;">查当前进程的页目录页表数据库，发现该</span><span style="font-size: 10.5pt; font-family: Verdana, sans-serif;">vaddr</span><span style="font-size: 10.5pt; font-family: 宋体;">对应的页目录表项为</span><span style="font-size: 10.5pt; font-family: Verdana, sans-serif;">0</span><span style="font-size: 10.5pt; font-family: 宋体;">，故产生异常；</span><span style="font-size: 10.5pt; font-family: Verdana, sans-serif;"><br /> &nbsp; &nbsp; * </span><span style="font-size: 10.5pt; font-family: 宋体;">在异常处理中，发现该</span><span style="font-size: 10.5pt; font-family: Verdana, sans-serif;">vaddr</span><span style="font-size: 10.5pt; font-family: 宋体;">对应的</span><span style="font-size: 10.5pt; font-family: Verdana, sans-serif;">vm_area_struct</span><span style="font-size: 10.5pt; font-family: 宋体;">已经存在，为</span><span style="font-size: 10.5pt; font-family: Verdana, sans-serif;">vaddr</span><span style="font-size: 10.5pt; font-family: 宋体;">对应的页目录表项分配一个页表；</span><span style="font-size: 10.5pt; font-family: Verdana, sans-serif;"><br /> &nbsp; &nbsp; * </span><span style="font-size: 10.5pt; font-family: 宋体;">随后从</span><span style="font-size: 10.5pt; font-family: Verdana, sans-serif;">free_list</span><span style="font-size: 10.5pt; font-family: 宋体;">找到一个</span><span style="font-size: 10.5pt; font-family: Verdana, sans-serif;">page</span><span style="font-size: 10.5pt; font-family: 宋体;">，将该</span><span style="font-size: 10.5pt; font-family: Verdana, sans-serif;">page</span><span style="font-size: 10.5pt; font-family: 宋体;">对应的物理页面物理首地址赋给</span><span style="font-size: 10.5pt; font-family: Verdana, sans-serif;">vaddr</span><span style="font-size: 10.5pt; font-family: 宋体;">对应的页表表项，很明显，此时的</span><span style="font-size: 10.5pt; font-family: Verdana, sans-serif;">vaddr</span><span style="font-size: 10.5pt; font-family: 宋体;">和</span><span style="font-size: 10.5pt; font-family: Verdana, sans-serif;">paddr</span><span style="font-size: 10.5pt; font-family: 宋体;">不是线性对应关系了；</span><span style="font-size: 10.5pt; font-family: Verdana, sans-serif;"><br /> &nbsp; &nbsp; * </span><span style="font-size: 10.5pt; font-family: 宋体;">将</span><span style="font-size: 10.5pt; font-family: Verdana, sans-serif;">page</span><span style="font-size: 10.5pt; font-family: 宋体;">从</span><span style="font-size: 10.5pt; font-family: Verdana, sans-serif;">free_list</span><span style="font-size: 10.5pt; font-family: 宋体;">中脱离；</span><span style="font-size: 10.5pt; font-family: Verdana, sans-serif;"><br /> &nbsp; &nbsp; * </span><span style="font-size: 10.5pt; font-family: 宋体;">异常处理返回；</span><span style="font-size: 10.5pt; font-family: Verdana, sans-serif;"><br /> &nbsp; &nbsp; * CPU</span><span style="font-size: 10.5pt; font-family: 宋体;">重新执行刚刚发生异常的指令</span><span style="font-size: 10.5pt; font-family: Verdana, sans-serif;">mov(eax, vaddr)</span><span style="font-size: 10.5pt; font-family: 宋体;">；</span><span style="font-size: 10.5pt; font-family: Verdana, sans-serif;"><br /> &nbsp; &nbsp; * CPU</span><span style="font-size: 10.5pt; font-family: 宋体;">获得</span><span style="font-size: 10.5pt; font-family: Verdana, sans-serif;">vaddr</span><span style="font-size: 10.5pt; font-family: 宋体;">这个虚地址，根据</span><span style="font-size: 10.5pt; font-family: Verdana, sans-serif;">CR3</span><span style="font-size: 10.5pt; font-family: 宋体;">寄存器指向的</span><span style="font-size: 10.5pt; font-family: Verdana, sans-serif;">current-&gt;pgd</span><span style="font-size: 10.5pt; font-family: 宋体;">，利用建立好的页目录页表数据库，找到其对应的物理内存地址；</span><span style="font-size: 10.5pt; font-family: Verdana, sans-serif;"><br /> &nbsp; &nbsp; * </span><span style="font-size: 10.5pt; font-family: 宋体;">将</span><span style="font-size: 10.5pt; font-family: Verdana, sans-serif;">eax</span><span style="font-size: 10.5pt; font-family: 宋体;">的内容写入</span><span style="font-size: 10.5pt; font-family: Verdana, sans-serif;">vaddr</span><span style="font-size: 10.5pt; font-family: 宋体;">对应的物理内存地址内；</span><span style="font-size: 10.5pt; font-family: Verdana, sans-serif;">&nbsp;&nbsp;<br /> <br /> 7. </span><span style="font-size: 10.5pt; font-family: 宋体;">用户进程释放内存</span><span style="font-size: 10.5pt; font-family: Verdana, sans-serif;">vaddr</span><span style="font-size: 10.5pt; font-family: 宋体;">，</span><span style="font-size: 10.5pt; font-family: Verdana, sans-serif;">free(vaddr)</span><span style="font-size: 10.5pt; font-family: 宋体;">：</span><span style="font-size: 10.5pt; font-family: Verdana, sans-serif;"><br /> <br /> &nbsp; &nbsp; * </span><span style="font-size: 10.5pt; font-family: 宋体;">找到该</span><span style="font-size: 10.5pt; font-family: Verdana, sans-serif;">vaddr</span><span style="font-size: 10.5pt; font-family: 宋体;">所在的</span><span style="font-size: 10.5pt; font-family: Verdana, sans-serif;">vm_area_struct</span><span style="font-size: 10.5pt; font-family: 宋体;">；</span><span style="font-size: 10.5pt; font-family: Verdana, sans-serif;"><br /> &nbsp; &nbsp; * </span><span style="font-size: 10.5pt; font-family: 宋体;">找到</span><span style="font-size: 10.5pt; font-family: Verdana, sans-serif;">vm_area_struct:start--end</span><span style="font-size: 10.5pt; font-family: 宋体;">对应的所有页目录页表项，清空对应的所有页表项；</span><span style="font-size: 10.5pt; font-family: Verdana, sans-serif;"><br /> &nbsp; &nbsp; * </span><span style="font-size: 10.5pt; font-family: 宋体;">释放这些页表项指向物理页面所对应的</span><span style="font-size: 10.5pt; font-family: Verdana, sans-serif;">page</span><span style="font-size: 10.5pt; font-family: 宋体;">，并将这些</span><span style="font-size: 10.5pt; font-family: Verdana, sans-serif;">page</span><span style="font-size: 10.5pt; font-family: 宋体;">加入到</span><span style="font-size: 10.5pt; font-family: Verdana, sans-serif;">free_list</span><span style="font-size: 10.5pt; font-family: 宋体;">队列中；</span><span style="font-size: 10.5pt; font-family: Verdana, sans-serif;"><br /> &nbsp; &nbsp; * </span><span style="font-size: 10.5pt; font-family: 宋体;">有必要还会清空一些页目录表项，并释放这些页目录表项指向的页表；</span><span style="font-size: 10.5pt; font-family: Verdana, sans-serif;"><br /> &nbsp; &nbsp; * </span><span style="font-size: 10.5pt; font-family: 宋体;">从</span><span style="font-size: 10.5pt; font-family: Verdana, sans-serif;">task-&gt;mm-&gt;mmap</span><span style="font-size: 10.5pt; font-family: 宋体;">链中删除该</span><span style="font-size: 10.5pt; font-family: Verdana, sans-serif;">vm_area_struct</span><span style="font-size: 10.5pt; font-family: 宋体;">并释放掉；</span><span style="font-size: 10.5pt; font-family: Verdana, sans-serif;"><br /> <br /> </span><span style="font-size: 10.5pt; font-family: 宋体;">综合说明：</span><span style="font-size: 10.5pt; font-family: Verdana, sans-serif;"><br /> <br /> &nbsp; &nbsp; * </span><span style="font-size: 10.5pt; font-family: 宋体;">可用物理内存就是</span><span style="font-size: 10.5pt; font-family: Verdana, sans-serif;">free_list</span><span style="font-size: 10.5pt; font-family: 宋体;">中各</span><span style="font-size: 10.5pt; font-family: Verdana, sans-serif;">page</span><span style="font-size: 10.5pt; font-family: 宋体;">对应的物理内存；</span><span style="font-size: 10.5pt; font-family: Verdana, sans-serif;"><br /> &nbsp; &nbsp; * </span><span style="font-size: 10.5pt; font-family: 宋体;">页目录页表数据库的主要目的是为</span><span style="font-size: 10.5pt; font-family: Verdana, sans-serif;">CPU</span><span style="font-size: 10.5pt; font-family: 宋体;">访问物理内存时转换</span><span style="font-size: 10.5pt; font-family: Verdana, sans-serif;">vaddr--&gt;paddr</span><span style="font-size: 10.5pt; font-family: 宋体;">使用，分配以及释放内存时不会用到，但是需要内核内存管理系统在合适时机为</span><span style="font-size: 10.5pt; font-family: Verdana, sans-serif;">CPU</span><span style="font-size: 10.5pt; font-family: 宋体;">建立好该库；</span><span style="font-size: 10.5pt; font-family: Verdana, sans-serif;"><br /> &nbsp; &nbsp; * </span><span style="font-size: 10.5pt; font-family: 宋体;">对于用户进程在</span><span style="font-size: 10.5pt; font-family: Verdana, sans-serif;">6</span><span style="font-size: 10.5pt; font-family: 宋体;">中获得的物理页面，有两个页表项对应，一个就是内核页目录页表数据库的某个</span><span style="font-size: 10.5pt; font-family: Verdana, sans-serif;">pte[i ]</span><span style="font-size: 10.5pt; font-family: 宋体;">，一个就是当前进程内核页目录页表数据库的某个</span><span style="font-size: 10.5pt; font-family: Verdana, sans-serif;"> pte[j]</span><span style="font-size: 10.5pt; font-family: 宋体;">，但是只有一个</span><span style="font-size: 10.5pt; font-family: Verdana, sans-serif;">page</span><span style="font-size: 10.5pt; font-family: 宋体;">和其对应。如果此时调度到其他进程，其他进程申请并访问某个内存，则不会涉及到该物理页面，因为其分配时首先要从</span><span style="font-size: 10.5pt; font-family: Verdana, sans-serif;"> free_list</span><span style="font-size: 10.5pt; font-family: 宋体;">中找一个</span><span style="font-size: 10.5pt; font-family: Verdana, sans-serif;">page</span><span style="font-size: 10.5pt; font-family: 宋体;">，而该物理页面对应的</span><span style="font-size: 10.5pt; font-family: Verdana, sans-serif;">page</span><span style="font-size: 10.5pt; font-family: 宋体;">已经从</span><span style="font-size: 10.5pt; font-family: Verdana, sans-serif;">free_list</span><span style="font-size: 10.5pt; font-family: 宋体;">中脱离出来了，因此不存在该物理页面被其他进程改写操作的情况。内核中通过</span><span style="font-size: 10.5pt; font-family: Verdana, sans-serif;">get_free_pages</span><span style="font-size: 10.5pt; font-family: 宋体;">等方式获取内存时，也不会涉及到该物理页面，原理同前所述。</span><img src ="http://www.cppblog.com/xieshuo/aggbug/204679.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/xieshuo/" target="_blank"> Torres</a> 2013-12-09 17:42 <a href="http://www.cppblog.com/xieshuo/archive/2013/12/09/204679.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>高性能JNI</title><link>http://www.cppblog.com/xieshuo/archive/2013/12/09/204678.html</link><dc:creator> Torres</dc:creator><author> Torres</author><pubDate>Mon, 09 Dec 2013 09:40:00 GMT</pubDate><guid>http://www.cppblog.com/xieshuo/archive/2013/12/09/204678.html</guid><wfw:comment>http://www.cppblog.com/xieshuo/comments/204678.html</wfw:comment><comments>http://www.cppblog.com/xieshuo/archive/2013/12/09/204678.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/xieshuo/comments/commentRss/204678.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/xieshuo/services/trackbacks/204678.html</trackback:ping><description><![CDATA[<span style="font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 19px; background-color: #ffffff;">from:&nbsp;</span><a href="http://www.cnblogs.com/whjiang/articles/1387364.html">http://www.cnblogs.com/whjiang/articles/1387364.html</a><br /><span style="font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 19px; background-color: #ffffff;"><br />1. 尽可能不要创建global reference和global weak reference. 创建这两类引用的JNI接口NewGlobalReference和NewGlobalWeakReference内部实现</span><br style="font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 19px; background-color: #ffffff;" /><span style="font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 19px; background-color: #ffffff;">有一个锁。这个锁使得在多处理器上的可扩展性非常差，因为各个线程都在等待这个锁。所以尽量不要在native保存java 对象的引用，情愿在每次</span><br style="font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 19px; background-color: #ffffff;" /><span style="font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 19px; background-color: #ffffff;">JNI call时都带点参数。当然，在native保持java对象的local reference是非常危险的，绝对不能那样干。</span><br style="font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 19px; background-color: #ffffff;" /><br style="font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 19px; background-color: #ffffff;" /><span style="font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 19px; background-color: #ffffff;">2. 尽量不要使用GetPrimitiveArrayCritical/ReleasePrimitiveArrayCritical来pin住Java内存。JVM本身没有提供任何只pin住一块Java内存而不影</span><br style="font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 19px; background-color: #ffffff;" /><span style="font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 19px; background-color: #ffffff;">响GC的操作，所以这个操作是会阻止GC进行的。作为补偿，ReleasePrimitiveArrayCritical会产生一次隐式的GC调用。这样就可能出现在需要GC的时</span><br style="font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 19px; background-color: #ffffff;" /><span style="font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 19px; background-color: #ffffff;">候无法GC，而在不需要GC时进行无意义GC的情况。另外，这两个操作的实现中在某些情况下也可能触发锁。解决方法：如果是小块内存的话，情愿使</span><br style="font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 19px; background-color: #ffffff;" /><span style="font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 19px; background-color: #ffffff;">用Get&lt;Type&gt;ArrayRegion和Set&lt;Type&gt;ArrayRegion来在native和Java之间复制内存。</span><br style="font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 19px; background-color: #ffffff;" /><br style="font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 19px; background-color: #ffffff;" /><span style="font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 19px; background-color: #ffffff;">3. 在Java appliation中尽量不要创建phantom reference或者soft reference。这些reference会极大的影响GC。</span><br style="font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 19px; background-color: #ffffff;" /><span style="font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 19px; background-color: #ffffff;">我们先来谈谈JVM的GC。GC分为minor GC和full GC。Java内存分为young和old两代。在young memory中，每个线程都有自己的内存分配块（不和其它</span><br style="font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 19px; background-color: #ffffff;" /><span style="font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 19px; background-color: #ffffff;">线程共享），而old memory是由所有线程共享的。minor GC只对young memory作GC，而full GC对所有内存都做GC。minor GC是可以多线程并行进行的</span><br style="font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 19px; background-color: #ffffff;" /><span style="font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 19px; background-color: #ffffff;">，而full GC默认只能单线程执行。所以，一次full GC需要的时间可以是minor GC是10倍以上（可以用-verbose:gc观察）。所以在一般应用中，</span><br style="font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 19px; background-color: #ffffff;" /><span style="font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 19px; background-color: #ffffff;">minor GC的次数应该是full GC的10倍左右是比较理想的。minor GC会将无法收集的对象移动到old memory中去。</span><br style="font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 19px; background-color: #ffffff;" /><p style="margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 19px; background-color: #ffffff;">minor GC不会对phantom reference和soft reference进行收集，只有full GC才会。这样的问题就是大量的这类对象积聚起来，产生许多的内存复制。</p><p style="margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 19px; background-color: #ffffff;">这样每次minor GC可能就基本上没有释放多少内存，使得full GC就会被频繁触发。可能出现minor GC和full GC次数1：1的情况，甚至全是full GC。</p><p style="margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 19px; background-color: #ffffff;">这样，无论是性能还是可扩展性都是非常差的。<br /></p><span style="font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 19px; background-color: #ffffff;">weak reference的影响好像小一些，但也应该尽量避免。</span><br style="font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 19px; background-color: #ffffff;" /><p style="margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 19px; background-color: #ffffff;">&nbsp;</p><p style="margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 19px; background-color: #ffffff;">在JNI开发中，使用这3种reference的主要目的是保证native资源的释放。因为java对象的finalize方法是不保证被调用的，所以必须用这些</p><span style="font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 19px; background-color: #ffffff;">reference来帮助实现native资源释放。为了避免上述的问题，一种可行的方法是将native资源serialize成一块内存，然后放到java对象中保存，从</span><br style="font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 19px; background-color: #ffffff;" /><span style="font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 19px; background-color: #ffffff;">而避免使用这些reference。</span><br style="font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 19px; background-color: #ffffff;" /><br style="font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 19px; background-color: #ffffff;" /><span style="font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 19px; background-color: #ffffff;">4. NIO是不错的Java和native之间share memory的方法。但要注意它的性能。首先一定要设置对big endian还是little endian，防止JVM做额外的</span><br style="font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 19px; background-color: #ffffff;" /><span style="font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 19px; background-color: #ffffff;">endian转换动作。其次是在启动JVM时一定要加上-server选项，否则nio性能会非常差。在-server mode下，nio性能大概比java数组慢30%~50%.在-</span><br style="font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 19px; background-color: #ffffff;" /><span style="font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 19px; background-color: #ffffff;">client mode下，性能差1倍以上。</span><br style="font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 19px; background-color: #ffffff;" /><br style="font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 19px; background-color: #ffffff;" /><span style="font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 19px; background-color: #ffffff;">5. 尽量不要在JNI去new Java String对象。这个比在java层new慢很多。</span><br style="font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 19px; background-color: #ffffff;" /><br style="font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 19px; background-color: #ffffff;" /><span style="font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 19px; background-color: #ffffff;">6. 对java大对象（比方说数组），一定要仔细的tune他的大小。一般来说，小对象对GC比较友好。因为对象分配时先看每个线程自己的young memory</span><br style="font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 19px; background-color: #ffffff;" /><span style="font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 19px; background-color: #ffffff;">，如果找的到足够大的内存的话，就分配。否则在old memory中分配。因为old memory是shared，所以可能有锁开销。而且old memory中的对象只有</span><br style="font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 19px; background-color: #ffffff;" /><span style="font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 19px; background-color: #ffffff;">full GC才能释放它。所以对象比较小是比较好的。JVM的内存分配算法是为小对象优化过的，大量小对象的分配是很高效的，所以不用怕把大对象拆小。</span><br style="font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 19px; background-color: #ffffff;" /><span style="font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 19px; background-color: #ffffff;">在某些情况下，如果知道对象会活的很久的话，就让它大一点，增加它直接分配在old memory中的概率。这样可以节约young GC拷贝这个对象到old&nbsp;</span><br style="font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 19px; background-color: #ffffff;" /><p style="margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 19px; background-color: #ffffff;">memory中的开销。</p><div></div><img src ="http://www.cppblog.com/xieshuo/aggbug/204678.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/xieshuo/" target="_blank"> Torres</a> 2013-12-09 17:40 <a href="http://www.cppblog.com/xieshuo/archive/2013/12/09/204678.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>第二章-编译和链接</title><link>http://www.cppblog.com/xieshuo/archive/2013/10/21/203851.html</link><dc:creator> Torres</dc:creator><author> Torres</author><pubDate>Mon, 21 Oct 2013 09:01:00 GMT</pubDate><guid>http://www.cppblog.com/xieshuo/archive/2013/10/21/203851.html</guid><wfw:comment>http://www.cppblog.com/xieshuo/comments/203851.html</wfw:comment><comments>http://www.cppblog.com/xieshuo/archive/2013/10/21/203851.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/xieshuo/comments/commentRss/203851.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/xieshuo/services/trackbacks/203851.html</trackback:ping><description><![CDATA[<div>第二章</div><div>编译和链接</div><div>这章比较笼统，都是概念，熟悉基本流程的人，建议不看。</div><div>&nbsp;</div><div>记录一些基本流程</div><div>&nbsp;</div><div>拿GCC来说</div><div>用GCC编译链接生成可执行文件的过程分为下面4个步骤</div><div>Prepressing，Compilation，Assembly，Linking</div><div>&nbsp;</div><div>Prepressing 预处理</div><div>从.c -&gt; .i (gcc -E)</div><div>主要是处理，前缀为&#8216;#&#8217;的语句</div><div>&nbsp;</div><div>define的直接替换</div><div>对define这种，从我观察应该是这样</div><div>对源文件类似.c直接扫描 看到define的符号直接加到表中</div><div>然后在替换的时候会做递归检查，直到符号是最终定义。</div><div>&nbsp;</div><div>所以这个与define的顺序没有太大关系了，只要不循环嵌套</div><div>&nbsp;</div><div>类似这种</div><div>#define M (N + 1)</div><div>#define N 2</div><div>&nbsp;</div><div>这种在用到M的时候，会先替换成 （N + 1）但是发现替换的表达式中还有未决symbol，那么</div><div>就再进行替换 （2 + 1）</div><div>&nbsp;</div><div>表中并不会直接写成 M （2 + 1），至少我看到的GCC行为是这样。</div><div>&nbsp;</div><div>include的也是直接导入</div><div>&nbsp;</div><div>另外预编译选项 #ifdef 之类的会处理掉，删掉所有注释</div><div>&nbsp;</div><div>#pragma是要被保留给编译器的，这是编译器选项，例如 pragma pack是用来指定字节对齐标准的</div><div>&nbsp;</div><div>Compilation 编译</div><div>从 .i -&gt; .s (gcc -S)</div><div>现在的GCC版本都把预编译和编译做到了一个可执行程序中 -&gt; ccl</div><div>&nbsp;</div><div>编译的主要过程</div><div>扫描，语法分析，语义分析，源代码优化，代码生成，目标代码优化</div><div>Source code --Scanner--&gt; Tokens --Parser--&gt; Syntax Tree</div><div>--Semantic Analyzer--&gt; Commented Syntax Tree --Source code Optimizer--&gt; Intermediate Representation</div><div>--Code Generator--&gt; Target Code --Code Optimizer--&gt;Final Target Code<br /><div>&nbsp;</div><div>Assembly 汇编</div><div>从 .s -&gt; .o (gcc -c) --&gt;汇编器as</div><div>&nbsp;</div><div>Linking 链接</div><div>ld做的事情</div><div>link的时候由于每个源文件都是单独编译，那么必须处理一些外来的symbol</div><div>包括函数和全局变量</div></div><div></div><img src ="http://www.cppblog.com/xieshuo/aggbug/203851.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/xieshuo/" target="_blank"> Torres</a> 2013-10-21 17:01 <a href="http://www.cppblog.com/xieshuo/archive/2013/10/21/203851.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>第一章-温故而知新</title><link>http://www.cppblog.com/xieshuo/archive/2013/10/18/203804.html</link><dc:creator> Torres</dc:creator><author> Torres</author><pubDate>Fri, 18 Oct 2013 11:42:00 GMT</pubDate><guid>http://www.cppblog.com/xieshuo/archive/2013/10/18/203804.html</guid><wfw:comment>http://www.cppblog.com/xieshuo/comments/203804.html</wfw:comment><comments>http://www.cppblog.com/xieshuo/archive/2013/10/18/203804.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/xieshuo/comments/commentRss/203804.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/xieshuo/services/trackbacks/203804.html</trackback:ping><description><![CDATA[<div>第一章</div>
<div>印象:</div>
<div>硬件PCI/ISA的架构</div>
<div>North Bridge相当于人的心脏，连接所有高速设备，CPU -&gt;大脑</div>
<div>南桥芯片则负责低速设备连接<br />&nbsp;&nbsp;</div>
<div></div>
<div>SMP<br />&nbsp;</div>
<div></div>
<div>中间层 是解决很多问题的大方向</div>
<div>Any problem in computer science can be resolved by another layer of indirection<br />&nbsp;<br />CPU密集型 IO密集型</div>
<div>这两种类型的Process，理论上优先级高的，也就是说最应该先得到CPU的是IO密集型</div>
<div></div>
<div>通俗的理解应该是IO密集型做完事情花的CPU时间最少，然后就会等待IO设备的反应，这样可以让设备性能最大化<br />&nbsp;</div>
<div></div>
<div>Memory</div>
<div>分段分页 MMU<br />&nbsp;</div>
<div></div>
<p>线程安全和线程模型<br />&nbsp;</p>
<div>其中线程安全有两件事情要注意</div>
<div>Semaphore</div>
<div>Mutex</div>
<div>上面这两个可以做成全局的，并不一定是By Process的，例如POSIX pthread在</div>
<div>对Mutex做attr设定的时候就可以指定为 shared process</div>
<div>也就是说一个Process可以加锁，另外一个可以释放他。</div>
<div>另外这种Mutex必须处在共享内存中，否则没办法访问。有亲缘关系的Process可以通过mmap一个匿名映射做到</div>
<div>anyway有很多方式了。<br />&nbsp;</div>
<div></div>
<div>Critical Section</div>
<div>这个是Inter Process的东西。<br />&nbsp;</div>
<div></div>
<div>关于线程互斥的lock的问题</div>
<div>RW lock就是对普通lock记录两个状态来供read or write操作选择<br />&nbsp;<br />属于线程本身的东西 TLS/Stack/Register<br />&nbsp;</div>
<div>有时候编译器会为了做优化</div>
<div>内存和寄存器的数据会出现不sync的状态。</div>
<div></div>
<div>即使你用lock来做保护,也不一定能OK。然后volatile就出现了。&nbsp;<br />&nbsp;</div>
<div>volatile最主要的作用就是thread内保证编译器不要做优化，防止这种不sync带来的问题。</div>
<div></div>
<div>一般是这样例如x变量，thread_1读到x变量放到了寄存器中，因为可能马上会再访问它，那么对x进行操作后就不会写回内存</div>
<div>这样即使你加了lock，这个时候lock也被释放掉了（操作完成），但是结果未能Sync，那么thread 2来访问x的时候，在内存</div>
<div>中拿到的值就变成dirty状态了。<br />&nbsp;
</div>
<div></div>
<div>另外一种过度优化就是CPU做的优化，有些上下语义无关的指令，CPU有可能会调整运行顺序。</div>
<div>书中有个经典样例</div>
<div>一段 Singleton pattern的double-check的代码</div>
<div></div>
<div>volatile T* pInst = NULL;</div>
<div>T* getInstance()</div>
<div>{</div>
<div><span style="white-space:pre"> </span>if (pInst == NULL)</div>
<div><span style="white-space:pre"> </span>{</div>
<div><span style="white-space:pre"> </span>lock();</div>
<div><span style="white-space:pre"> </span>if (pInst == NULL)</div>
<div><span style="white-space:pre"> </span>pInst = new T();</div>
<div><span style="white-space:pre"> </span>unlock();</div>
<div><span style="white-space:pre"> </span>}</div>
<div><span style="white-space:pre"> </span>return pInst;</div>
<div>}<br /><br />&nbsp;</div>
<div></div>
<div>这里有两点</div>
<div>第一，double-check 也就是双if能避免过多的无用的get lock，降低消耗</div>
<div>对临界区需要做保护的资源，可以提前去取状态，如果符合自己的预期，而且短时间不会有变化，那么就不用去拿锁了</div>
<div>不知道为啥我想到了unlikely，但仔细想一下，功能完全不同。<br />&nbsp;</div>
<div></div>
<div>第二点也就是要说的CPU的过度优化</div>
<div>这里已经是声明volatile了，所以没有寄存器和内存不sync的问题</div>
<div>但是由于这里new需要先 malloc出空间，然后call T的constructor。</div>
<div>所以有可能会发生这种情况，malloc出空间后，把地址付给pInst，然后去做初始化；</div>
<div>这样就有可能另外一个线程取得的object是没有被完全初始化好的，是否会出问题depend on T的具体实现了。</div>
<div></div>
<div>许多CPU提供了barrier指令用来解决上面提到的问题。<br />&nbsp;</div>
<div></div>
<div></div>
<div>线程模型</div>
<div>这个东西，我看了下，开始没看明白，这边书这个东西没讲清楚，后来去网上找了些资料。用户线程和内核线程的对应关系取决于调度单位。</div>
<div>也就是说内核把什么东西当做一个调度单位<br />&nbsp;</div>
<div>拿Linux来说吧，Process是线程集和资源集<br />&nbsp;</div>
<div>调度的时候，那些共享资源的Task（thread）之间的调度肯定比那些跨Process不共享资源的thread做context switch消耗的资源</div>
<div>多得多。<br />&nbsp;</div>
<div></div>
<div>基于调度消耗之类的考量</div>
<div></div>
<div>模型分为下面几种<br />&nbsp;</div>
<div>一对一，也就是说 user space create出来的线程就是和kernel的调度单位相同，称一一对应<br />&nbsp;</div>
<div>一对多，应该是这样一种情况，kernel看到的是Process，userspace自己实现出来自己的thread，这个thread，kernel是不知道的</div>
<div>调度的时候kernel负责分批CPU给他能看到的Process，上层userspace自己来调度分配这个Process获得的CPU time给这个process中的</div>
<div>各个线程。</div>
<div>这样的分配就可以保证在一定的时间内只需要做一些register和stack的切换，不会有memory等等的switch。</div>
<div>坏处是上面的thread只要一个被suspend，那么这个Process里面的其他thread也就被suspend住了，一般上层调度程序</div>
<div>不会假定其他的thread能run，所以一般会是kernel把CPU time给其他process<br />&nbsp;</div>
<div></div>
<div>多对多，就是一种混合的情况了，我想到了Android，但是Android是一对一模型，dalvik会保证Java thread对应下面一个</div>
<div>native thread，想说的是，这种虚拟机架构可以做成多对多的样子，一个native thread run一个JVM，JVM开出来很多Java Thread，</div>
<div>JVM负责调度这些Java Thread，Native负责调度JVM所在的Thread。</div>
<div>不知道我有没有讲错。<br />
<br />
</div>
<div></div>
<div></div><img src ="http://www.cppblog.com/xieshuo/aggbug/203804.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/xieshuo/" target="_blank"> Torres</a> 2013-10-18 19:42 <a href="http://www.cppblog.com/xieshuo/archive/2013/10/18/203804.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>程序员自我修养-读书笔记</title><link>http://www.cppblog.com/xieshuo/archive/2013/10/14/203710.html</link><dc:creator> Torres</dc:creator><author> Torres</author><pubDate>Mon, 14 Oct 2013 09:07:00 GMT</pubDate><guid>http://www.cppblog.com/xieshuo/archive/2013/10/14/203710.html</guid><wfw:comment>http://www.cppblog.com/xieshuo/comments/203710.html</wfw:comment><comments>http://www.cppblog.com/xieshuo/archive/2013/10/14/203710.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/xieshuo/comments/commentRss/203710.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/xieshuo/services/trackbacks/203710.html</trackback:ping><description><![CDATA[&nbsp; &nbsp; &nbsp;之前就翻过一次，这次再看看，期望这次能读到我想知道的东西...<br />&nbsp; &nbsp; &nbsp;这个书的名字我自己觉得有点屌丝风格了，Orz，期望编者勿怪<img src ="http://www.cppblog.com/xieshuo/aggbug/203710.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/xieshuo/" target="_blank"> Torres</a> 2013-10-14 17:07 <a href="http://www.cppblog.com/xieshuo/archive/2013/10/14/203710.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>LTZ看书之APUE14</title><link>http://www.cppblog.com/xieshuo/archive/2013/06/07/200852.html</link><dc:creator> Torres</dc:creator><author> Torres</author><pubDate>Fri, 07 Jun 2013 10:52:00 GMT</pubDate><guid>http://www.cppblog.com/xieshuo/archive/2013/06/07/200852.html</guid><wfw:comment>http://www.cppblog.com/xieshuo/comments/200852.html</wfw:comment><comments>http://www.cppblog.com/xieshuo/archive/2013/06/07/200852.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/xieshuo/comments/commentRss/200852.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/xieshuo/services/trackbacks/200852.html</trackback:ping><description><![CDATA[伪终端.<br />
<p>这个是Muxd一直用的东西<br />相当于一个双向PIPE<br />Process A open ptm得到fdm，然后fork出process B，process B open pts得到fds，然后将0,1,2都dup到fds上<br />那么fds就变成了process B的控制终端<br />后面再process B中做标准IO操作的时候就会像PIPE直接影响到fdm<br />终端行规程在pts之上<br /><br />没什么特别要记录的，在网上search了下，贴个链接，里面会介绍一些基本概念.<br /><a href="http://www.cnblogs.com/Anker/archive/2012/12/25/2832568.html">http://www.cnblogs.com/Anker/archive/2012/12/25/2832568.html</a> </p><img src ="http://www.cppblog.com/xieshuo/aggbug/200852.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/xieshuo/" target="_blank"> Torres</a> 2013-06-07 18:52 <a href="http://www.cppblog.com/xieshuo/archive/2013/06/07/200852.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>LTZ看书之APUE13</title><link>http://www.cppblog.com/xieshuo/archive/2013/06/07/200842.html</link><dc:creator> Torres</dc:creator><author> Torres</author><pubDate>Fri, 07 Jun 2013 06:40:00 GMT</pubDate><guid>http://www.cppblog.com/xieshuo/archive/2013/06/07/200842.html</guid><wfw:comment>http://www.cppblog.com/xieshuo/comments/200842.html</wfw:comment><comments>http://www.cppblog.com/xieshuo/archive/2013/06/07/200842.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/xieshuo/comments/commentRss/200842.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/xieshuo/services/trackbacks/200842.html</trackback:ping><description><![CDATA[<p>终端IO<br />每个终端都有输入输出队列<br />队列都有长度，如果输入超过输入队列MAX_INPUT长度，大多数unix系统会回显响铃来处理。<br />但是对于输出队列来讲，虽然输出队列也有长度，但是一旦写不进去的时候，写进程会suspend掉<br />直至有空闲空间</p>
<p>终端行规程 terminal line discipline<br />会帮忙做规范处理</p>
<p>终端设备属性 -&gt;termios</p>
<p>struct termios {<br />&nbsp;tcflag_t c_iflag;<br />&nbsp;tcflag_t c_oflag;<br />&nbsp;tcflag_t c_cflag;<br />&nbsp;tcflag_t c_lflag;<br />&nbsp;cc_t c_line;<br />&nbsp;cc_t c_cc[NCCS];<br />};</p>
<p>local flag影响驱动程序和用户之间的接口<br />Android上tcflag_t-&gt;<br />typedef unsigned int tcflag_t;</p>
<p>cc_t<br />typedef unsigned char cc_t;</p>
<p>control flag中很多选项标志都是用几位标识然后用或来做选择</p>
<p>isatty的实现，借助tcgetattr的出错机制，成功返回0；否则返回-1，带上ENOTTY</p>
<p>int<br />isatty (int&nbsp; fd)<br />{<br />&nbsp; struct termios term;</p>
<p>&nbsp; return tcgetattr (fd, &amp;term) == 0;<br />}</p>
<p>Anyway，终端IO很复杂...</p><img src ="http://www.cppblog.com/xieshuo/aggbug/200842.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/xieshuo/" target="_blank"> Torres</a> 2013-06-07 14:40 <a href="http://www.cppblog.com/xieshuo/archive/2013/06/07/200842.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>LTZ看书之APUE12</title><link>http://www.cppblog.com/xieshuo/archive/2013/06/06/200830.html</link><dc:creator> Torres</dc:creator><author> Torres</author><pubDate>Thu, 06 Jun 2013 09:22:00 GMT</pubDate><guid>http://www.cppblog.com/xieshuo/archive/2013/06/06/200830.html</guid><wfw:comment>http://www.cppblog.com/xieshuo/comments/200830.html</wfw:comment><comments>http://www.cppblog.com/xieshuo/archive/2013/06/06/200830.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/xieshuo/comments/commentRss/200830.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/xieshuo/services/trackbacks/200830.html</trackback:ping><description><![CDATA[<p>IPC<br /><br />首先讲到的是PIPE，这个并不陌生，相互通信的Process必须具有关系，一般是同父亲的<br />然后讲到了协同进程<br />基本是说有一个进程专门用来接收输入，然后处理，然后返回结果<br />这个就可以用PIPE来实现</p>
<p>创建两个PIPE，一个用于输入给协同进程，另外一个用于接收协同进程的输出<br />fork之后在子进程中将标准输入输出都dup到管道上</p>
<p>而协同进程的写法可以比较common，只用关心标准输入输出。<br />PIPE在写的时候如果有多个写进程，那么写的数据小于 PIPE_BUF 则不会乱序，否则自己应该就需要做同步了。</p>
<p>然后就是FIFO，这个就是用mkfifo创建一个file，大家都去用。<br />PIPE和FIFO都是半双工的</p>
<p>XSI IPC -&gt;即之前System V IPC<br />消息队列 信号量 共享存储器</p>
<p>在无关进程之间共享存储段，一个是使用上面V系统shm；另外一个是使用mmap将同一文件map到他们自己的进程空间。<br /><br />另外就是网络IPC了<br />算是复习下吧，之前这块儿看的比较多<br />int socket(int domain, int type, int protocol)<br />domain标识address family -&gt; AF_INET, AF_INET6, AF_UNIX(AF_LOCAL), AF_UNSPEC<br />type标识socket类型 -&gt; SOCK_DGRAM(UDP), SOCK_RAW(IP), SOCK_SEQPACKET, SOCK_STREAM(TCP)<br /><br />一般protocol都设置为0，一般address family和type就能确认要使用的protocol<br /><br />SOCK_SEQPACKET和SOCK）STREAM很像，前一个提供面向数据报文的服务，而后面这种则是面对流。<br />SOCK_SEQPACKET使用场景SCTP，贴一个SCTP的简要介绍。<br /><a href="http://www.cnblogs.com/qlee/archive/2011/07/13/2105717.html">http://www.cnblogs.com/qlee/archive/2011/07/13/2105717.html</a><br /><br />涉及网络就必须要清楚字节序的问题，字节序与字符编码是两件不同的事情，都要想清楚的，但是要提一下UTF-8这是一种专门设计用来做网络传输的字符编码<br />无需关心字节序的问题，所以传输的上层数据可以用UTF-8，就不用担心local host和remote host的主机字节序不一样而导致乱序了。<br /><br />但是很多协议头必须做符合TCP/IP协议的字节序规范，TCP/IP是big endian<br />关于Big endian和Litter endian我比较容易忘记具体的样子，但是他的出发点是低地址，低地址装的是最高有效字节那么就是big endian，否则就是litter endian。<br /><br />关于socket有几个可能比较模糊的地方<br />connect时，也就是client端，如果fd没有绑定到某个地址，那么kernel会帮忙将其绑定到默认地址; 所以bind这件事情是Client和Server都需要做的事情，调用listen之前也一样<br />然后accept的时候，如果你关心对方的地址，那么提供addr(足够)和len，返回的时候就能知道。<br />另外UDP(SOCK_DGRAM)也可以Call connect，之后就可以直接call send/write，而不必每次都call sendto指定对端地址。<br /><br />sendto中flag一般给0，如果是紧急数据给MSG_OOB<br /><br />文件描述符的传输，目的是想让不同的process在不同的文件描述符中共享文件表。<br />所以做法上系统会这样，传输文件表指针然后放到接收端的第一个可用的文件描述符上。<br />这个我在linux上没找到实现，因为这个功能还是有蛮多替代方案的。<br /></p>  <img src ="http://www.cppblog.com/xieshuo/aggbug/200830.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/xieshuo/" target="_blank"> Torres</a> 2013-06-06 17:22 <a href="http://www.cppblog.com/xieshuo/archive/2013/06/06/200830.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>LTZ看书之APUE11</title><link>http://www.cppblog.com/xieshuo/archive/2013/06/05/200818.html</link><dc:creator> Torres</dc:creator><author> Torres</author><pubDate>Wed, 05 Jun 2013 08:59:00 GMT</pubDate><guid>http://www.cppblog.com/xieshuo/archive/2013/06/05/200818.html</guid><wfw:comment>http://www.cppblog.com/xieshuo/comments/200818.html</wfw:comment><comments>http://www.cppblog.com/xieshuo/archive/2013/06/05/200818.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/xieshuo/comments/commentRss/200818.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/xieshuo/services/trackbacks/200818.html</trackback:ping><description><![CDATA[<p>13章在讲Daemon Process，没什么特别好写的。<br />14 -&gt;高级IO</p>
<p>低速系统调用，也就是有信号发生会返回 errno 为 EINTR的</p>
<p>磁盘文件IO虽然有延时，但是这个不能算是低速系统调用</p>
<p>APUE介绍的低速系统调用<br />PIPE，终端设备，网络设备 读写 <br />读无数据/写无空间(例如TCP卡Congestion window)</p>
<p>打开某些特殊文件<br />加记录锁的文件读写<br />ioctl，IPC<br /></p>
<p><br />文件锁又叫做 byte-range locking，针对特定的文件区域，适合数据库文件<br />Posix标准<br />int fcntl(int fd, int cmd, .../* struct flock* flockptr */)<br />cmd -&gt; F_GETLK,F_SETLK,F_SETLKW<br />F_SETLKW是F_SETLK的Blocking版本 W means wait</p>
<p>重要数据结构是struct flock -&gt;<br />struct flock {<br />&nbsp;short l_type;<br />&nbsp;short l_whence;<br />&nbsp;off_t l_start;<br />&nbsp;off_t l_len;<br />&nbsp;pid_t l_pid;<br />&nbsp;__ARCH_FLOCK_PAD<br />};</p>
<p>锁定整个file的方式: l_whence = SEEK_SET, l_start = 0, l_len = 0</p>
<p>l_type的两类lock<br />F_RDLCK，F_WRLCK这两种锁的特性很像rw lock</p>
<p>不过与读写锁不一样的是或者这样讲<br />Posix.1没有规定下面这种情况: process A在某文件区间上设置了一把读锁；process B尝试在这个文件区间加上写锁的时候suspend；process C再尝试获取读锁，如果允许</p>
<p>process C拿到读锁，那么process B将会可能永远拿不到写锁，活活饿死</p>
<p>pthread里面的rw lock的实现会在这种情况下suspend掉process C的读锁请求；但是目前文件区域锁的实现我不太确定</p>
<p>这里看文件区域锁还是比较容易带来deadlock的<br />例如process A锁住F1的某个区域，然后去锁F2的一个区域，这时候F2的这个区域被process B锁住，那么process A就会suspend，如果这个时候process B过来要锁F1的这个区域<br />就会发生deadlock<br /></p>
<p><br />关于文件区域锁的继承和释放<br />1.fork后，文件区域锁并不继承，继承了就完了，不同的process就有可能同时干同一件事情，把数据搞坏<br />2.close(fd)后 fd对应的文件锁就被释放了，文件锁挂在inode上，close的时候kernel会去扫描对应的inode上与这个PID相关的lock，释放掉，而并不去关心是哪个文件描述符或</p>
<p>者是哪个文件表，这很重要，因为lockf中并不记录fd，他们只是弱关联关系，这个很重要。<br />3.exec后，文件锁会继承原来执行程序的锁(fork之后拿到的lock)，如果fd带有close-on-exec那么根据第二条，这个fd对应的file上的锁都会被释放。</p>
<p><br />后面讲了STREAMS，感觉linux上用到的不多，需要在编译kernel时动态加载</p>
<p>IO多路转接，主要是为了实现polling既所谓的轮询<br />主要函数有select，pselect，poll，epoll<br />select也会算是低速系统调用，那么就有可能被信号打断<br />pselect有参数可以设定信号屏蔽集，也提供更高精度的timer</p>
<p>poll的方式与select有不太一样的地方，但是功能相同，epoll更适合大数据量。</p>
<p>readv和writev<br />记住下面两条就够了<br />一个称为scatter read(散步读)；另外一个称为gather write(聚集写)<br />这两个函数会面对一个buffer链表。<br /></p>
<p><br />readn和writen<br />这个比较像现在Android里面socket的read和write方式，保证能read/write n byte数据，在内部做循环<br />我比较好奇这两个是否会处理signal，想来应该是会处理的，遇到EINTR帮忙重启就好了</p>
<p>我没有找到Bionic库的实现<br /></p>
<p><br />存储映射IO<br />这个很重要，mmap用的很多，映射到process空间的位置在 stack以下，heap以上的部分，map完后返回低地址。</p>
<p>#include&lt;sys/mman.h&gt;<br />void* mmap(void* addr, size_t len, int prot, int flag, int filedes, off_t off)</p>
<p>prot -&gt; PROT_READ,PROT_WRITE,PROT_EXEC,PROT_NONE<br />prot指定的对映射存储区的保护不能超过文件的open权限</p>
<p>在 flag为 MAP_FIXED的时候OS会保证分配的memory起始地址为addr，否则只是给OS一个建议。<br />一般建议addr给0，让OS来决定。</p>
<p>MAP_SHARED是说对映射区域的存储(write)会导致修改该文件。<br />MAP_PRIVATE则是对映射区域的操作会常见一个映射文件的副本。<br /></p>
<p><br />后面有个例子用了lseek<br />使用lseek增加文件长度的方式，先lseek一个值，如果这个值大于文件本身的长度，那么下一次写就会加长该文件，并且在文件<br />中形成一个空洞，未写过的内容全部读为0。<br />mmap只能map文件的最大长度，超过的地方没办法同步到文件。</p><img src ="http://www.cppblog.com/xieshuo/aggbug/200818.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/xieshuo/" target="_blank"> Torres</a> 2013-06-05 16:59 <a href="http://www.cppblog.com/xieshuo/archive/2013/06/05/200818.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>