﻿<?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++博客- 驭风万里无垠-随笔分类-Linux</title><link>http://www.cppblog.com/skyscribe/category/10932.html</link><description /><language>zh-cn</language><lastBuildDate>Sun, 19 Feb 2012 08:30:07 GMT</lastBuildDate><pubDate>Sun, 19 Feb 2012 08:30:07 GMT</pubDate><ttl>60</ttl><item><title>ruby学习笔记《一》</title><link>http://www.cppblog.com/skyscribe/archive/2012/02/19/ruby-study-0.html</link><dc:creator>skyscribe</dc:creator><author>skyscribe</author><pubDate>Sun, 19 Feb 2012 07:58:00 GMT</pubDate><guid>http://www.cppblog.com/skyscribe/archive/2012/02/19/ruby-study-0.html</guid><wfw:comment>http://www.cppblog.com/skyscribe/comments/165976.html</wfw:comment><comments>http://www.cppblog.com/skyscribe/archive/2012/02/19/ruby-study-0.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/skyscribe/comments/commentRss/165976.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/skyscribe/services/trackbacks/165976.html</trackback:ping><description><![CDATA[看得再多也不如自己动手试，最近有闲就打算认真研究一下ruby语言了。<a href="http://pragprog.com/the-pragmatic-programmer">Pragmatic programmer</a>中说，需要一年学一门新语言一遍改造思想，去年浅浅的学了javascript的皮毛，今年可以看看ruby这
个有lisp之风的OO语言了。<br />
<br />
<ul>
     <li>安装环境</li>
</ul>
第一个想到的是apt-get来下载了，得到的是一个交互式解析器和编译器。和python的比较类似，不过ruby的交互程序是个单独的程序叫做irb。<br />
<blockquote>
<div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #000000; ">skyscribe:</span><span style="color: #000000; ">~</span><span style="color: #000000; ">$&nbsp;ruby&nbsp;</span><span style="color: #000000; ">--</span><span style="color: #000000; ">version<br />
ruby&nbsp;</span><span style="color: #000000; ">1.8</span><span style="color: #000000; ">.</span><span style="color: #000000; ">7</span><span style="color: #000000; ">&nbsp;(</span><span style="color: #000000; ">2011</span><span style="color: #000000; ">-</span><span style="color: #000000; ">06</span><span style="color: #000000; ">-</span><span style="color: #000000; ">30</span><span style="color: #000000; ">&nbsp;patchlevel&nbsp;</span><span style="color: #000000; ">352</span><span style="color: #000000; ">)&nbsp;[i686</span><span style="color: #000000; ">-</span><span style="color: #000000; ">linux]<br />
skyscribe:</span><span style="color: #000000; ">~</span><span style="color: #000000; ">$&nbsp;irb<br />
irb(main):</span><span style="color: #000000; ">001</span><span style="color: #000000; ">:</span><span style="color: #000000; ">0</span><span style="color: #000000; ">&gt;</span><span style="color: #000000; ">&nbsp;puts&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">hello</span><span style="color: #000000; ">"</span><span style="color: #000000; "><br />
hello<br />
</span><span style="color: #000000; ">=&gt;</span><span style="color: #000000;">&nbsp;nil<br />
<br />
</span></div>
</blockquote>可惜得到的不是比较新的版本。<br />
<br />
不
过很快想起翻翻<a href="http://en.wikipedia.org/wiki/Ruby_%28programming_language%29">
wiki</a>，还是用rvm方便的多。教程比较简单，参考它的<a href="http://beginrescueend.com/">quick installation guide</a>就可。第一次尝试的时候用apt-get安装了没有purge，导致总是安装到root用户造
成&#8220;permission denied"的问题。<br />
<br />
安装好之后，所有的东西都在$HOME/.rvm下边，比较干脆。<br />
<div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #000000;"><br />
</span><blockquote><span style="color: #000000; ">skyscribe:</span><span style="color: #000000; ">~</span><span style="color: #000000; ">$&nbsp;rvm&nbsp;install&nbsp;</span><span style="color: #000000; ">1.9</span><span style="color: #000000; ">.</span><span style="color: #000000; ">3</span><span style="color: #000000;"></span><br />
<span style="color: #000000; ">skyscribe:</span><span style="color: #000000; ">~</span><span style="color: #000000;">$&nbsp;rvm&nbsp;list</span><br />
<span style="color: #000000;"></span><br />
<span style="color: #000000;">rvm&nbsp;rubies</span><br />
<span style="color: #000000;"></span><br />
<span style="color: #000000; ">&nbsp;&nbsp;&nbsp;ruby</span><span style="color: #000000; ">-</span><span style="color: #000000; ">1.9</span><span style="color: #000000; ">.</span><span style="color: #000000; ">3</span><span style="color: #000000; ">-</span><span style="color: #000000;">p125&nbsp;[&nbsp;i686&nbsp;]</span><br />
<span style="color: #000000;"></span><br />
<span style="color: #000000; ">#&nbsp;Default&nbsp;ruby&nbsp;not&nbsp;</span><span style="color: #0000FF; ">set</span><span style="color: #000000; ">.&nbsp;Try&nbsp;</span><span style="color: #000000; ">'</span><span style="color: #000000; ">rvm&nbsp;alias&nbsp;create&nbsp;default&nbsp;&lt;ruby&gt;</span><span style="color: #000000; ">'</span><span style="color: #000000;">.</span><br />
<span style="color: #000000;"></span><br />
<span style="color: #000000; ">#&nbsp;</span><span style="color: #000000; ">=&gt;</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">-</span><span style="color: #000000;">&nbsp;current</span><br />
<span style="color: #000000; ">#&nbsp;</span><span style="color: #000000; ">=*</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">-</span><span style="color: #000000; ">&nbsp;current&nbsp;</span><span style="color: #000000; ">&amp;&amp;</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">default</span><span style="color: #000000;"></span><br />
<span style="color: #000000; ">#&nbsp;&nbsp;</span><span style="color: #000000; ">*</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">-</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">default</span><span style="color: #000000;"></span><br />
<span style="color: #000000;"></span><br />
<span style="color: #000000; ">skyscribe:</span><span style="color: #000000; ">~</span><span style="color: #000000; ">$&nbsp;rvm&nbsp;alias&nbsp;create&nbsp;</span><span style="color: #0000FF; ">default</span><span style="color: #000000; ">&nbsp;ruby</span><span style="color: #000000; ">-</span><span style="color: #000000; ">1.9</span><span style="color: #000000; ">.</span><span style="color: #000000; ">3</span><span style="color: #000000; ">-</span><span style="color: #000000;">p125</span><br />
<span style="color: #000000; ">Creating&nbsp;alias&nbsp;</span><span style="color: #0000FF; ">default</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">for</span><span style="color: #000000; ">&nbsp;ruby</span><span style="color: #000000; ">-</span><span style="color: #000000; ">1.9</span><span style="color: #000000; ">.</span><span style="color: #000000; ">3</span><span style="color: #000000; ">-</span><span style="color: #000000;">p125.</span><br />
<span style="color: #000000; ">Recording&nbsp;alias&nbsp;</span><span style="color: #0000FF; ">default</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">for</span><span style="color: #000000; ">&nbsp;ruby</span><span style="color: #000000; ">-</span><span style="color: #000000; ">1.9</span><span style="color: #000000; ">.</span><span style="color: #000000; ">3</span><span style="color: #000000; ">-</span><span style="color: #000000;">p125.</span><br />
<span style="color: #000000; ">Creating&nbsp;</span><span style="color: #0000FF; ">default</span><span style="color: #000000; ">&nbsp;links</span><span style="color: #000000; ">/</span><span style="color: #000000;">files</span><br /><br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000; "></span><span style="color: #000000; "><div>skyscribe:~$ cat &gt;&gt; ~/.bashrc <br />[[ -s "$HOME/.rvm/scripts/rvm" ]] &amp;&amp; . "$HOME/.rvm/scripts/rvm" # This loads RVM into a shell session.<br />^C<br />skyscribe:~$ bash<br />skyscribe:~$ rvm use 1.9.3<br />Using /home/skyscribe/.rvm/gems/ruby-1.9.3-p125<br />skyscribe:~$ ruby -v<br />ruby 1.9.3p125 (2012-02-16 revision 34643) [i686-linux]</div></span></div><br />
<span style="color: #000000; "></span></blockquote></div>
<br />
<ul>
     <li>熟悉和上手</li>
</ul>
官方的文档是最好的参考，推荐<a href="http://rubykoans.com/">ruby koans</a>,下载下来，解压后，是个典型的TDD学习材料，不断运行<br />
<blockquote>
<div>
<div>&nbsp;ruby path_to_enlightenment.rb</div></div></blockquote><div><div>koans 会遍历每一个test case直到全部完毕，大概需要2个小时以上的时间方可全部完工。中间的注释和THINK ABOUT的部分比较有意思，感悟比较深刻的是以下一些点：<br /><blockquote><ul><li>完完全全的OO，所有东西皆为对象</li><li>两种基本的collection，hash和array基本对应于python的dict和array</li><li>函数调用可以不必添加括号，除非可能引发歧义或者解析错误</li><li>函数参数可以包含block，支持lambda和closure<br /></li><li>bool类型更简单，只有false和nil与false等价，其余全部是true</li><li>控制结构有unless</li><li>类定义是开放式的，便于非侵入式设计，当然也可以允许修改builtin</li><li>每一个对象都有object id</li><li>symbol和string可以互相转化构造</li><li>method的调用可以用send 的方法发送message - proxy变得极度容易</li><li>module可以被class include从而包含方法， 便于mixin设计</li><li>instance variable和class variable 定义方便快捷</li><li>regular expresion的和python极为相似<br /></li></ul></blockquote></div></div><blockquote><div>
</div>
</blockquote><img src ="http://www.cppblog.com/skyscribe/aggbug/165976.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/skyscribe/" target="_blank">skyscribe</a> 2012-02-19 15:58 <a href="http://www.cppblog.com/skyscribe/archive/2012/02/19/ruby-study-0.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Unix文本处理之利器－awk/gawk</title><link>http://www.cppblog.com/skyscribe/archive/2011/01/02/awk.html</link><dc:creator>skyscribe</dc:creator><author>skyscribe</author><pubDate>Sun, 02 Jan 2011 12:32:00 GMT</pubDate><guid>http://www.cppblog.com/skyscribe/archive/2011/01/02/awk.html</guid><wfw:comment>http://www.cppblog.com/skyscribe/comments/137894.html</wfw:comment><comments>http://www.cppblog.com/skyscribe/archive/2011/01/02/awk.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/skyscribe/comments/commentRss/137894.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/skyscribe/services/trackbacks/137894.html</trackback:ping><description><![CDATA[日常在shell中使用awk基本是家常便饭了，但是详细的写一些小程序还是第一次，总体是下来，还是深深得被这门年龄比自己都要大的工具语言的魅力所折服（<a  href="http://groups.engin.umd.umich.edu/CIS/course.des/cis400/awk/awk.html#history">since 1977</a>）。作者中最引人注目的当属鼎鼎大名的<a  href="https://secure.wikimedia.org/wikipedia/en/wiki/Brian_Kernighan">Brian W. Kernighan</a> (即K的简称来源）。目前所用的版本大多是gawk或者nawk.<br><br>作为一门微型且完整的编程语言，awk可以用数行代码就完成其他语言需要数倍的LOC才能完成的工作。其设计哲学也是比较特殊的，核心是data－driven的，并且采用了和C类似的语法来组织。它最核心的思想应该是如下两点：<br>
<ul>
    <li>pattern-action 结构 借由强大的正则表达式来匹配pattern，然后执行pattern对应的操作</li>
    <li>Record/Field 处理模型&nbsp; 所有的输入数据都根据制定的record separator 分割成 record, 然后没一个record再根据field separator 分割为fields. POSIX 定义的 field separator可以为正则表达式，而gawk可以允许record separator同时为正则表达式</li>
</ul>
引发我花点时间来仔细研究awk的起因是这样的，我们的程序在做profiling的时候，发现原来用shell写的脚本分析一次话费的时间太长。初看了下那个脚本，大概的逻辑是要扫名所有的log文件，按照时间戳将关注的时间所耗费的时间提取出来，计算平均值，波动等最终画出曲线图。<br><br>整体的脚本有几个部分（python＋bash），处理一次40MB的log文件需要耗费40分钟～1个小时，这显然超出了预期；中间一个处理很长的部分是grep某个时间段的信息然后按照报表格式写入到中间文件中。在想能否优化这一节的时候，忽然就想起了模式匹配来（学习Haskell的最深印象），于是大致翻了一下awk，发现很容易通过模式匹配使得按行处理，同时记录中间的信息，而一个时间段恰好和awk的record概念吻合。<br><br>花了2个小时研读了下awk的函数语法，自定义自己的时间截取函数（gawk的strftime很有用，尤其我们发现记录有跳跃要自动补全中间的数据记录时），通过三个pattern截取需要的信息，30分钟写出来awk的代码来。<br><br>所幸的是，其它的shell脚本都不需要任何改动，重新跑一次，3s就处理完了原来40MB的文件，看来这点时间投入还是相当值得的。<br><br>有兴趣的可参考：<br>&nbsp;&nbsp;&nbsp;&nbsp; <a  href="http://www.gnu.org/manual/gawk/gawk.html">http://www.gnu.org/manual/gawk/gawk.html</a><br><br>PS：awk的另一作者<a  href="https://secure.wikimedia.org/wikipedia/en/wiki/Peter_J._Weinberger">Winberger</a> 供职于google。<br>&nbsp;<br><br><img src ="http://www.cppblog.com/skyscribe/aggbug/137894.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/skyscribe/" target="_blank">skyscribe</a> 2011-01-02 20:32 <a href="http://www.cppblog.com/skyscribe/archive/2011/01/02/awk.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>GCC4.5的profile mode</title><link>http://www.cppblog.com/skyscribe/archive/2010/05/09/GCC4_5ProfileMode.html</link><dc:creator>skyscribe</dc:creator><author>skyscribe</author><pubDate>Sun, 09 May 2010 07:16:00 GMT</pubDate><guid>http://www.cppblog.com/skyscribe/archive/2010/05/09/GCC4_5ProfileMode.html</guid><wfw:comment>http://www.cppblog.com/skyscribe/comments/114920.html</wfw:comment><comments>http://www.cppblog.com/skyscribe/archive/2010/05/09/GCC4_5ProfileMode.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/skyscribe/comments/commentRss/114920.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/skyscribe/services/trackbacks/114920.html</trackback:ping><description><![CDATA[GCC最近发布了4.5版本，对于C++的支持除了更为丰富的0x特性支持外（参考<a href="http://gcc.gnu.org/onlinedocs/libstdc++/manual/status.html#status.iso.200x">这里</a>），<br>还增加了一个新的profile模式（尚处于试验阶段），可以根据程序运行状态给出关于STL使用的一些优化建议。<br><br>参看如下的描述：<br>
<div style="margin-left: 40px;">
<ul>
    <li>
    <p>An experimental <a href="http://gcc.gnu.org/onlinedocs/libstdc++/manual/profile_mode.html">
    profile mode </a> has been added. This is an implementation of
    many C++ standard library constructs with an additional analysis
    layer that gives performance improvement advice based on
    recognition of suboptimal usage patterns. For example,
    </p>
    <pre>#include &lt;vector&gt;<br>int main() <br>{<br>  std::vector&lt;int&gt; v;<br>  for (int k = 0; k &lt; 1024; ++k) <br>    v.insert(v.begin(), k);<br>}<br></pre>
    <p>
    When instrumented via the profile mode, can return suggestions about
    the initial size and choice of the container used as follows:
    </p>
    <pre>vector-to-list: improvement = 5: call stack = 0x804842c ...<br>    : advice = change std::vector to std::list<br>vector-size: improvement = 3: call stack = 0x804842c ...<br>    : advice = change initial container size from 0 to 1024<br></pre>
    <p>
    These constructs can be substituted for the normal libstdc++
    constructs on a piecemeal basis, or all existing components can be
    transformed via the <code>-D_GLIBCXX_PROFILE</code> macro.
    </p>
    </li>
</ul>
</div>
这个profile mode的主要作用就是根据代码实际运行状况给出关于STL的使用优化建议。有点遗憾的是，该profile方法是intrusive的，必须添加-D_GLBCXX_PROFILE来重新编译所有的代码。<br><br>Profile mode的提出源于09年CGO的一篇<a href="http://ieeexplore.ieee.org/xpl/freeabs_all.jsp?reload=true&amp;arnumber=4907670">paper</a>，作者里边出现了华人的名字（根据拼音来判断）;作者地址填的显然是Purdue大学的：<br>&nbsp;&nbsp;&nbsp; Dept. of Comput. Sci., Purdue Univ., West。<br><br>GCC的Profiler对C++的支持一贯停留在和C同样的水平；由于C++模板机制和OO的存在使得很多时候分析profiling结果的意义被大大削弱。<br>这个针对STL的profile mode还是很值得期待的。<br><br><br>  <img src ="http://www.cppblog.com/skyscribe/aggbug/114920.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/skyscribe/" target="_blank">skyscribe</a> 2010-05-09 15:16 <a href="http://www.cppblog.com/skyscribe/archive/2010/05/09/GCC4_5ProfileMode.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>TCP几个小选项引起的&amp;ldquo;古怪&amp;rdquo;问题</title><link>http://www.cppblog.com/skyscribe/archive/2009/10/19/98967.html</link><dc:creator>skyscribe</dc:creator><author>skyscribe</author><pubDate>Mon, 19 Oct 2009 11:18:00 GMT</pubDate><guid>http://www.cppblog.com/skyscribe/archive/2009/10/19/98967.html</guid><wfw:comment>http://www.cppblog.com/skyscribe/comments/98967.html</wfw:comment><comments>http://www.cppblog.com/skyscribe/archive/2009/10/19/98967.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/skyscribe/comments/commentRss/98967.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/skyscribe/services/trackbacks/98967.html</trackback:ping><description><![CDATA[<p><font face="微软雅黑" size="3">许久不查TCP相关的问题，今天下班前被一同事拦下要帮忙，说他碰到了<strong>奇怪</strong>的问题。</font></p> <p><font face="微软雅黑" size="3">拿下wireshark抓到的包一看，半天才明白他所说的疑惑是指他每次发送一个数据包，通信对端就回了一个ACK包，由此就直接怀疑是否对方关闭连接或者建立新的连接了。</font></p> <p><font face="微软雅黑" size="3">花了半天功夫，总算解释清楚ACK包其实是很正常的数据包（带数据的包也有ACK标志的，wireshark只不过是把不带数据的纯协议ACK包在描述信息里边直接标出来了而已），同事也算是个很老练的Java高手了，对这点基本的小问题有一些疑义，起初是让我有点疑惑的。</font></p> <p><font face="微软雅黑" size="3"></font>&nbsp;</p> <p><font face="微软雅黑" size="3">不过总算讨论清楚了这个ACK没有任何问题，本以为他遇到的根本不是问题，岂料他又抛出了一个问题：</font></p> <p><font face="微软雅黑" size="3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 既然ACK不是造成问题的症结，为什么我要发送三个数据包，只有前一个的ACK收到之后，下一个包才能发的出去？每个数据包的发送和受到ACK的时间间隔大于15ms，而他们的系统需求规定那个间隔必须小于15ms。</font></p> <p><font face="微软雅黑" size="3">这个问题算是有点深入一点了，即使认为15ms的延迟是正常的TCP协议栈行为，那么他的三个包只能顺序发出去就有些诧异了，而且据说是上千个设备都是如此规律，那么这种规律本身就不正常了。</font></p> <p><font face="微软雅黑" size="3">首先的怀疑当然是TCP的buffer满了，导致send发送阻塞，不过TCP的数据内容倒是显示没有那个问题，因为他发送的三个包每个都只有几十个字节。</font></p> <p><font face="微软雅黑" size="3">剩下的情况大概只有一种，就是应用程序手工设置了buffer大小，甚至是设置了SND_BUF为0（其实只要小于他的最小PDU长度），导致他的协议交互变成了“停等协议”了；因为每一次发送的时候，buffer缓冲都不够用，所以send调用必然是被阻塞，直到收到前一个包的ACK数据然后才能继续；不熟悉TCP协议栈的，看到这种现象，就怀疑是那个ACK回复的有问题了。</font></p> <p><font face="微软雅黑" size="3"></font>&nbsp;</p> <p><font face="微软雅黑" size="3">最后他又提出了一个问题，为什么有时候他一次发送了三个包，抓包的时候只有两个？恰巧这又是一个TCP控制选项的问题，鼎鼎大名的“Nagle算法“在底下运作的结果了。</font></p> <p><font face="微软雅黑" size="3">为了确认猜测不是问题，让他Show了一下代码，确认两种现象对应的是不同的socket，可惜的是后一个socket的创建代码是无法看到了。</font></p> <p><font face="微软雅黑" size="3"></font>&nbsp;</p> <p><font face="微软雅黑" size="3">这些小选项引起都是非常基本的TCP协议栈原理性知识，为何习惯了Java抽象和自带类库的人会被这种问题产生的表面现象所疑惑？</font></p><img src ="http://www.cppblog.com/skyscribe/aggbug/98967.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/skyscribe/" target="_blank">skyscribe</a> 2009-10-19 19:18 <a href="http://www.cppblog.com/skyscribe/archive/2009/10/19/98967.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>利用LD_PRELOAD发现程序潜在的问题</title><link>http://www.cppblog.com/skyscribe/archive/2009/06/30/88940.html</link><dc:creator>skyscribe</dc:creator><author>skyscribe</author><pubDate>Tue, 30 Jun 2009 14:05:00 GMT</pubDate><guid>http://www.cppblog.com/skyscribe/archive/2009/06/30/88940.html</guid><wfw:comment>http://www.cppblog.com/skyscribe/comments/88940.html</wfw:comment><comments>http://www.cppblog.com/skyscribe/archive/2009/06/30/88940.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/skyscribe/comments/commentRss/88940.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/skyscribe/services/trackbacks/88940.html</trackback:ping><description><![CDATA[Solaris上，常常可以用LD_PRELOAD辅助mdb做一些调试、测试工作，可以发现一些其它手段难以发现的问题；最近就遇到一个。<br><br>事情源于替换了程序中的某个基础部分之后，程序运行起来占用的物理内存有了较为显著的增加，却难以一下子拿出来个让人信服的原因。于是自然想到了去看一下程序真正运行的时候，某一部分内存是谁分配的。之前用 pmap -xalsF pid发现【heap】部分有显著增加，又不是在新加入的那个动态库里边。<br>Solaris上有强大的mdb，辅助不同的模块可以得出很多有意思的结论，其中libumem.so即可以查看内存的分配的情况，并可以检测是否有内存泄漏。<br>启动的方法很简便：<br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><font face="courier new,courier,monospace">export UMEM_DEBUG=default<br></font><font face="courier new,courier,monospace">export UMEM_LOGGING=transaction</font><br><span style="color: #000000;">LD_PRELOAD</span><span style="color: #000000;">=/</span><span style="color: #000000;">lib</span><span style="color: #000000;">/</span><span style="color: #000000;">libumem.so<br>export&nbsp;LD_PRELOAD</span></div>
然后在此shell中启动程序，新打开一个终端，同样设置好LD_PRELOAD（否则会提示错误），<br>查找正运行的程序的进程号（调试的程序），生成一个core文件：<br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #000000;">ps&nbsp;</span><span style="color: #000000;">-</span><span style="color: #000000;">ef&nbsp;</span><span style="color: #000000;">|</span><span style="color: #000000;">&nbsp;grep&nbsp;</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">appname</span><span style="color: #000000;">&gt;</span><span style="color: #000000;"><br>gcore&nbsp;</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">pid</span><span style="color: #000000;">&gt;</span><span style="color: #000000;"><br>ls&nbsp;core.</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">pid</span><span style="color: #000000;">&gt;</span></div>
用mdb打开新生成的core文件，第一行应该提示加载了libumem.so.<br>接下来，用libumem.so提供的walker和dcmds就可以查询程序运行以来到产生core文件的那一时间点丰富的内存信息了.<br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #000000;">mdb&nbsp;core.pid<br></span><span style="color: #000000;">&gt;</span><span style="color: #000000;">::findleaks<br></span><span style="color: #000000;">&gt;</span><span style="color: #000000;">::umalog<br></span><span style="color: #000000;">&gt;</span><span style="color: #000000;">::umem_log</span></div>
更多可用的命令，可以用::dmods -l查看。<br><br>整个过程非常繁杂，因为应用程序比较大，分配内存的log实在是太多了，但是突然发现运行目录下边多了不少core文件，一下子奇怪了，之前可是花费了很多时间在提高代码质量上，按道理不应该会有core产生了。打开这些core，用pstack，居然发现某个模块启动的子进程在调用free的地方abort了，按图索骥查看代码，在某个旮旯里边，几年没人动的小角落里，发现分配内存的地方：<br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #0000ff;">char</span><span style="color: #000000;">*</span><span style="color: #000000;">&nbsp;path1&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;getenv(</span><span style="color: #000000;">"</span><span style="color: #000000;">MYENV</span><span style="color: #000000;">"</span><span style="color: #000000;">);<br></span><span style="color: #0000ff;">char</span><span style="color: #000000;">&nbsp;path2[]&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">bin/logDir/log.xxx</span><span style="color: #000000;">"</span><span style="color: #000000;"><br></span><span style="color: #0000ff;">char</span><span style="color: #000000;">*</span><span style="color: #000000;">&nbsp;path&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;malloc(</span><span style="color: #0000ff;">sizeof</span><span style="color: #000000;">(path1)&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">sizeof</span><span style="color: #000000;">(path2));<br>strcpy(path,&nbsp;path1);<br>strcat(path,&nbsp;path2);<br><img src="http://www.cppblog.com/Images/dot.gif">.<br><br>free(path);<br>exit(</span><span style="color: #000000;">0</span><span style="color: #000000;">);<br><br><img src="http://www.cppblog.com/Images/dot.gif">.</span></div>
原来最初写这块纯C代码的人打了马虎眼，分配的内存有问题，导致free的时候出问题，但正常情况下，这里的exit之后，进程也就退出了，居然没有core文件出来，导致这个Bug居然被隐藏了数年。<br><br>libumem和LD_PRELOAD居然把它挖了出来，马上修改之。<br><br>所谓&#8220;祸患常积于忽微&#8221;，最不起眼的地方，往往会衍生一些麻烦，不时咬你一口。<br>讨厌的"legacy code without evolution/refactoring/test......"，每个负责任的职业程序员都应该去深思<br><br>【注】Linux上似乎也有libumem.so，但是却没有pstack/mdb这些好用的工具，只有valgrind/gdb了；solaris上不但有mdb/dtrace,还有dbx,虽然gdb也是可用的<br><br><img src ="http://www.cppblog.com/skyscribe/aggbug/88940.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/skyscribe/" target="_blank">skyscribe</a> 2009-06-30 22:05 <a href="http://www.cppblog.com/skyscribe/archive/2009/06/30/88940.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>