﻿<?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++博客-天之道</title><link>http://www.cppblog.com/zhenglinbo/</link><description>享受编程的乐趣。</description><language>zh-cn</language><lastBuildDate>Sat, 04 Apr 2026 05:41:43 GMT</lastBuildDate><pubDate>Sat, 04 Apr 2026 05:41:43 GMT</pubDate><ttl>60</ttl><item><title>浅谈Java内部类</title><link>http://www.cppblog.com/zhenglinbo/archive/2013/09/28/203473.html</link><dc:creator>hoshelly</dc:creator><author>hoshelly</author><pubDate>Sat, 28 Sep 2013 06:26:00 GMT</pubDate><guid>http://www.cppblog.com/zhenglinbo/archive/2013/09/28/203473.html</guid><wfw:comment>http://www.cppblog.com/zhenglinbo/comments/203473.html</wfw:comment><comments>http://www.cppblog.com/zhenglinbo/archive/2013/09/28/203473.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/zhenglinbo/comments/commentRss/203473.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/zhenglinbo/services/trackbacks/203473.html</trackback:ping><description><![CDATA[<br />什么是内部类呢？顾名思义，内部类就是在类中可以定义另一个的类。内部类是外部对象的一个成员，同样具有public , private 和 protected的访问权限。<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: #0000FF; ">public</span>&nbsp;<span style="color: #0000FF; ">class</span>&nbsp;Test<br />{<br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">public</span>&nbsp;<span style="color: #0000FF; ">static</span>&nbsp;<span style="color: #0000FF; ">void</span>&nbsp;main(String[]&nbsp;args)<br />&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Family&nbsp;my&nbsp;=&nbsp;<span style="color: #0000FF; ">new</span>&nbsp;Family(&#8220;Jonh",130);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;my.getMsg();<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br />}<br /><span style="color: #0000FF; ">class</span>&nbsp;Family<br />{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Family(String name,int weight){&nbsp;<span style="color: #0000FF; ">this</span>.f&nbsp;=&nbsp;<span style="color: #0000FF; ">new</span>&nbsp;Father(name,weight);&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">private</span>&nbsp;<span style="color: #0000FF; ">class</span>&nbsp;Father<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">private</span>&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;weight;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">private</span>&nbsp;String&nbsp;name;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Father(String&nbsp;n,<span style="color: #0000FF; ">int</span>&nbsp;w)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">this</span>.name&nbsp;=&nbsp;n;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">this</span>.weight&nbsp;=&nbsp;w;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">public</span>&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;getWeight()<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;weight;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">public</span>&nbsp;String&nbsp;getName()<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;name;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">private</span>&nbsp;Father&nbsp;f;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">public</span>&nbsp;<span style="color: #0000FF; ">void</span>&nbsp;getMsg()<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println("Name:&nbsp;"+f.getName()+"\nWeight:&nbsp;"+f.getWeight());<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />}</div><div></div><div>类Family 中有一个Father类，声明为private，表明在Family类中可以创建一个实例对象，这个Father专属于Family类。普通的（非内部）类不能声明为private或者protected，只能声明为public。因此这样的代码是不被允许的：<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 />-->Family.Father&nbsp;a&nbsp;=&nbsp;my.<span style="color: #0000FF; ">new</span>&nbsp;Father("Jonh",150);</div><br />如果要使用上述代码，只要修改内部类的访问权限就可以了，如去掉private权限，则默认为包访问权限，同一个包中的类都可以访问它，而不是只能从Family类才能访问。<br /><br /><div style="background-color: #eeeeee; font-size: 13px; border: 1px solid #cccccc; padding: 4px 5px 4px 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: #0000FF; ">public</span>&nbsp;<span style="color: #0000FF; ">class</span>&nbsp;test<br />{<br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">public</span>&nbsp;<span style="color: #0000FF; ">static</span>&nbsp;<span style="color: #0000FF; ">void</span>&nbsp;main(String[]&nbsp;args)<br />&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Family&nbsp;my&nbsp;=&nbsp;<span style="color: #0000FF; ">new</span>&nbsp;Family("Jonh",130);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;my.getMsg();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Family.Father&nbsp;a&nbsp;=&nbsp;my.<span style="color: #0000FF; ">new</span>&nbsp;Father("Jonh",150);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println("Name:&nbsp;"+a.getName()+"\nWeight:&nbsp;"+a.getWeight());<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br />}</div>在上述代码中，在创建内部类对象时，语法为：Family.Father a = my.new Father("Jonh",150); 说明内部类对象的创建是基于一个外部类对象（my），也就是说内部类对象必须依附于一个外部类对象。</div><br />内部类可以出现在所属类的方法内或任意作用域内。像下面的代码将内部类嵌入在方法内：<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: #0000FF; ">public</span>&nbsp;<span style="color: #0000FF; ">class</span>&nbsp;test<br />{<br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">public</span>&nbsp;<span style="color: #0000FF; ">static</span>&nbsp;<span style="color: #0000FF; ">void</span>&nbsp;main(String[]&nbsp;args)<br />&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Family&nbsp;my&nbsp;=&nbsp;<span style="color: #0000FF; ">new</span>&nbsp;Family();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;my.getMsg("Jonh",150);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br />}<br /><span style="color: #0000FF; ">class</span>&nbsp;Family<br />{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Family(){&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">public</span>&nbsp;<span style="color: #0000FF; ">void</span>&nbsp;getMsg(String&nbsp;s,<span style="color: #0000FF; ">int</span>&nbsp;n)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">class</span>&nbsp;Father<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">private</span>&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;weight;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">private</span>&nbsp;String&nbsp;name;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Father(String&nbsp;n,<span style="color: #0000FF; ">int</span>&nbsp;w)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">this</span>.name&nbsp;=&nbsp;n;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">this</span>.weight&nbsp;=&nbsp;w;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">public</span>&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;getWeight()<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;weight;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">public</span>&nbsp;String&nbsp;getName()<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;name;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Father&nbsp;f&nbsp;=&nbsp;<span style="color: #0000FF; ">new</span>&nbsp;Father(s,n);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println("Name:&nbsp;"+f.getName()+"\nWeight:&nbsp;"+f.getWeight());<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />}</div><br /><br /><strong>闭包<br /></strong><br />内部类可以访问外部类的成员变量（即使是private），如在Family类中添加成员变量height，在Father类中定义一个方法 getHeight()，则能成功访问这个height变量，而在外部类中不能访问内部类中的成员变量。<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 />--><br /><span style="color: #0000FF; ">class</span>&nbsp;Family<br />{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">private</span>&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;height&nbsp;=&nbsp;180;&nbsp;<span style="color: #008000; ">/*</span><span style="color: #008000; ">定义外部类属性height</span><span style="color: #008000; ">*/</span><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Family(String&nbsp;name,<span style="color: #0000FF; ">int</span>&nbsp;weight){&nbsp;<span style="color: #0000FF; ">this</span>.f&nbsp;=&nbsp;<span style="color: #0000FF; ">new</span>&nbsp;Father(name,weight);&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">private</span>&nbsp;<span style="color: #0000FF; ">class</span>&nbsp;Father<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">private</span>&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;weight;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">private</span>&nbsp;String&nbsp;name;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Father(String&nbsp;n,<span style="color: #0000FF; ">int</span>&nbsp;w)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">this</span>.name&nbsp;=&nbsp;n;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">this</span>.weight&nbsp;=&nbsp;w;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">public</span>&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;getWeight()<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;weight;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">public</span>&nbsp;String&nbsp;getName()<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;name;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">public</span>&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;getHeight()<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;height;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">/*</span><span style="color: #008000; ">访问外部类的属性height</span><span style="color: #008000; ">*/</span><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">private</span>&nbsp;Father&nbsp;f;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">public</span>&nbsp;<span style="color: #0000FF; ">void</span>&nbsp;getMsg()<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println("Name:&nbsp;"+f.getName()+"\nWeight:&nbsp;"+f.getWeight()+"\nHeight:&nbsp;"+f.getHeight());<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />}<br /><span style="color: #0000FF; ">public</span>&nbsp;<span style="color: #0000FF; ">class</span>&nbsp;test<br />{<br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">public</span>&nbsp;<span style="color: #0000FF; ">static</span>&nbsp;<span style="color: #0000FF; ">void</span>&nbsp;main(String[]&nbsp;args)<br />&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Family&nbsp;my&nbsp;=&nbsp;<span style="color: #0000FF; ">new</span>&nbsp;Family("Jonh",130);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;my.getMsg();<br />&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;<span style="color: #008000;">/*</span><span style="color: #008000;">&nbsp;not&nbsp;allowed&nbsp;</span><span style="color: #008000;">*/</span><div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; width: 98%; word-break: break-all;">&nbsp;&nbsp;<span style="color: #008000; ">/*</span><span style="color: #008000; ">&nbsp;System.out.println(my.weight);&nbsp;</span><span style="color: #008000; ">*/</span></div>&nbsp; &nbsp; }<br />}</div><br />如果把内部类单独拿到外面来声明，那么要使用外部类的属性如height，就要先创建外部类的对象，再由对象调用其height属性，现在由于内部类处于外部类中，所以在程序调用时不必再创建外部类的对象，直接就可以使用height，这样减少了一部分内存空间的开销。<br /><br /><strong>嵌套static类</strong><br /><br />在类内部定义static类，称为嵌套static类。<br />我们可以直接创建嵌套类，而不必依赖于某个外部类对象。嵌套类无法调用外部对象的方法、也无法读取或修改外部对象的数据。<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: #0000FF; ">public</span>&nbsp;<span style="color: #0000FF; ">class</span>&nbsp;Test{<br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">public</span>&nbsp;<span style="color: #0000FF; ">static</span>&nbsp;<span style="color: #0000FF; ">void</span>&nbsp;main(String[]&nbsp;args){<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Father.Son&nbsp;John&nbsp;=&nbsp;<span style="color: #0000FF; ">new</span>&nbsp;Father.Son();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;John.display();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />}<br /><br /><span style="color: #0000FF; ">class</span>&nbsp;Father{<br />&nbsp;&nbsp;<span style="color: #008000; ">/*</span><span style="color: #008000; ">嵌套类</span><span style="color: #008000; ">*/</span><br />&nbsp;<span style="color: #0000FF; ">static</span>&nbsp;<span style="color: #0000FF; ">class</span>&nbsp;Son{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">public</span>&nbsp;<span style="color: #0000FF; ">void</span>&nbsp;display(){<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println("I&nbsp;am&nbsp;his&nbsp;son.");<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;}<br />}</div><br /><strong>总结</strong><br />1. 内部类丰富了类的组织形式；<br />2. 内部类实现了闭包。<br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><img src ="http://www.cppblog.com/zhenglinbo/aggbug/203473.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/zhenglinbo/" target="_blank">hoshelly</a> 2013-09-28 14:26 <a href="http://www.cppblog.com/zhenglinbo/archive/2013/09/28/203473.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>栈和堆（转）</title><link>http://www.cppblog.com/zhenglinbo/archive/2013/09/27/203451.html</link><dc:creator>hoshelly</dc:creator><author>hoshelly</author><pubDate>Fri, 27 Sep 2013 01:13:00 GMT</pubDate><guid>http://www.cppblog.com/zhenglinbo/archive/2013/09/27/203451.html</guid><wfw:comment>http://www.cppblog.com/zhenglinbo/comments/203451.html</wfw:comment><comments>http://www.cppblog.com/zhenglinbo/archive/2013/09/27/203451.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/zhenglinbo/comments/commentRss/203451.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/zhenglinbo/services/trackbacks/203451.html</trackback:ping><description><![CDATA[<span style="color: #333333; font-family: 'courier new', courier; line-height: 25px; background-color: #ffffff;">摘抄自：</span><span style="color: #333333; font-family: 'courier new', courier; line-height: 25px; background-color: #ffffff;">http://www.cnblogs.com/vamei&nbsp;</span><br /><span style="color: #333333; font-family: 'courier new', courier; line-height: 25px; background-color: #ffffff;"><br />当程序文件运行为进程的时候，进程在内存中得到空间(进程自己的小房间)。每个进程空间按照如下方式分为不同区域:<br /></span><img src="http://www.cppblog.com/images/cppblog_com/zhenglinbo/5.jpg" width="402" height="878" alt="" /><br /><span style="color: #333333; font-family: 'courier new', courier; line-height: 25px; text-align: center; background-color: #ffffff;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 内存空间<br /><br /></span><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; color: #333333; font-family: verdana, Arial, Helvetica, sans-serif; line-height: 25px; background-color: #ffffff;"><span style="margin: 0px; padding: 0px; font-family: 'courier new', courier;">Text区域用来储存指令(instruction)，来告诉程序每一步的操作。Global Data用于存放全局变量，stack用于存放局部变量，heap用于存放动态变量 (dynamic variable. 程序利用malloc系统调用，直接从内存中为dynamic variable开辟空间)。<span style="margin: 0px; padding: 0px; color: #ff0000;">Text</span>和<span style="margin: 0px; padding: 0px; color: #ff0000;">Global data</span>在进程一开始的时候就确定了，并在整个进程中保持<span style="margin: 0px; padding: 0px; color: #ff0000;">固定大小</span>。</span></p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; color: #333333; font-family: verdana, Arial, Helvetica, sans-serif; line-height: 25px; background-color: #ffffff;"><span style="margin: 0px; padding: 0px; font-family: 'courier new', courier;">&nbsp;</span></p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; color: #333333; font-family: verdana, Arial, Helvetica, sans-serif; line-height: 25px; background-color: #ffffff;"><span style="margin: 0px; padding: 0px; font-family: 'courier new', courier;"><span style="margin: 0px; padding: 0px; color: #ff0000;">Stack<span style="margin: 0px; padding: 0px; color: #000000;">(</span>栈<span style="margin: 0px; padding: 0px; color: #000000;">)</span></span>以<span style="margin: 0px; padding: 0px; color: #ff0000;">stack frame</span>为单位。当程序调用函数的时候，比如main()函数中调用inner()函数，stack会向下增长一个stack frame。Stack frame中存储该函数的<span style="margin: 0px; padding: 0px; color: #ff0000;">参数</span>和<span style="margin: 0px; padding: 0px; color: #ff0000;">局部变量</span>，以及该函数的<span style="margin: 0px; padding: 0px; color: #ff0000;">返回地址<span style="margin: 0px; padding: 0px; color: #000000;">(return address)</span></span>。此时，计算机将控制权从main()转移到inner()，inner()函数处于<span style="margin: 0px; padding: 0px; color: #ff0000;">激活</span>(active)状态。位于Stack最下方的frame和Global Data就构成了当前的环境(context)。激活函数可以从中调用需要的变量。典型的编程语言都只允许你使用位于stack最下方的frame ，而不允许你调用其它的frame (这也符合stack结构&#8220;先进后出&#8221;的特征。但也有一些语言允许你调用stack的其它部分，相当于允许你在运行inner()函数的时候调用main()中声明的局部变量，比如Pascal)。当函数又进一步调用另一个函数的时候，一个新的frame会继续增加到stack下方，控制权转移到新的函数中。当激活函数<span style="margin: 0px; padding: 0px; color: #ff0000;">返回</span>的时候，会从stack中<span style="margin: 0px; padding: 0px; color: #ff0000;">弹出</span>(<span style="margin: 0px; padding: 0px; color: #ff0000;">pop</span>，就是读取并删除)该frame，并根据frame中记录的返回地址，将控制权交给返回地址<span style="margin: 0px; padding: 0px; color: #ff0000;">所指向的指令</span>(比如从inner()函数中返回，继续执行main()中赋值给main2的操作)。</span></p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; color: #333333; font-family: verdana, Arial, Helvetica, sans-serif; line-height: 25px; background-color: #ffffff;"><span style="margin: 0px; padding: 0px; font-family: 'courier new', courier;">下图是stack在运行过程中的变化，箭头表示stack增长的方向，每个方块代表一个stack frame。开始的时候我们有一个为main()服务的frame，随着调用inner()，我们为inner()增加一个frame。在inner()返回时，我们再次只有main()的frame，直到最后main()返回，其返回地址为空，所以进程结束。<br /><br /></span></p><span style="color: #333333; font-family: 'courier new', courier; line-height: 25px; text-align: center; background-color: #ffffff;"><img src="http://www.cppblog.com/images/cppblog_com/zhenglinbo/6.jpg" border="0" alt="" width="808" height="338" /><br /></span>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;<span style="color: #333333; font-family: 'courier new', courier; line-height: 25px; text-align: center; background-color: #ffffff;">stack变化<br /><br /><br /></span><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; color: #333333; font-family: verdana, Arial, Helvetica, sans-serif; line-height: 25px; background-color: #ffffff;"><span style="margin: 0px; padding: 0px; font-family: 'courier new', courier;">在进程运行的过程中，通过调用和返回函数，<span style="margin: 0px; padding: 0px; color: #ff0000;">控制权</span>不断在函数间转移。进程可以在调用函数的时候，原函数的stack frame中保存有在我们离开时的状态，并为新的函数开辟所需的stack frame空间。在调用函数返回时，该函数的stack frame所占据的空间随着stack frame的弹出而清空。进程再次回到原函数的stack frame中保存的状态，并根据返回地址所指向的指令继续执行。上面过程不断继续，stack不断增长或减小，直到main()返回的时候，stack完全清空，进程结束。</span></p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; color: #333333; font-family: verdana, Arial, Helvetica, sans-serif; line-height: 25px; background-color: #ffffff;"><span style="margin: 0px; padding: 0px; font-family: 'courier new', courier;">&nbsp;</span></p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; color: #333333; font-family: verdana, Arial, Helvetica, sans-serif; line-height: 25px; background-color: #ffffff;"><span style="margin: 0px; padding: 0px; font-family: 'courier new', courier;">&nbsp;当程序中使用malloc的时候，<span style="margin: 0px; padding: 0px; color: #ff0000;">heap<span style="margin: 0px; padding: 0px; color: #000000;">(</span>堆<span style="margin: 0px; padding: 0px; color: #000000;">)</span></span><span style="margin: 0px; padding: 0px; color: #000000;">会</span>向上增长，其增长的部分就成为malloc从内存中分配的空间。malloc开辟的空间会一直存在，直到我们用free系统调用来释放，或者进程结束。一个经典的错误是<span style="margin: 0px; padding: 0px; color: #ff0000;">内存泄漏</span>(<span style="margin: 0px; padding: 0px; color: #ff0000;">memory leakage</span>), 就是指我们没有释放不再使用的heap空间，导致heap不断增长，而内存可用空间不断减少。</span></p><p style="margin-top: 10px; margin-bottom: 10px; padding: 0px; color: #333333; font-family: verdana, Arial, Helvetica, sans-serif; line-height: 25px; background-color: #ffffff;"><span style="margin: 0px; padding: 0px; font-family: 'courier new', courier;">由于stack和heap的大小则会随着进程的运行增大或者变小，当stack和heap增长到两者相遇时候，也就是内存空间图中的<span style="margin: 0px; padding: 0px; color: #ff0000;">蓝色区域</span>(unused area)完全消失的时候，进程会出现<span style="margin: 0px; padding: 0px; color: #ff0000;">栈溢出</span>(<span style="margin: 0px; padding: 0px; color: #ff0000;">stack overflow</span>)的错误，导致进程终止。在现代计算机中，内核一般都会为进程分配足够多的蓝色区域，如果我们即时清理的话，stack overflow是可以避免的。但是，在进行一些矩阵运算的时候，由于所需的内存很大，依然可能出现stack overflow的情况。一种解决方式是增大内核分配给每个进程的内存空间。如果依然不能解决问题的话，我们就需要增加物理内存。<br /><br /></span></p><span style="color: #333333; font-family: 'courier new', courier; line-height: 25px; text-align: center; background-color: #ffffff;"><br />堆和栈的区别：<br /><br /><br /></span><span style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;">2.1申请方式&nbsp;&nbsp;&nbsp;&nbsp;</span><br style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;" /><span style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;">&nbsp; stack:&nbsp;&nbsp;&nbsp;&nbsp;</span><br style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;" /><span style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;">&nbsp; 由系统自动分配。&nbsp;&nbsp; 例如，声明在函数中一个局部变量&nbsp;&nbsp; int&nbsp;&nbsp; b;&nbsp;&nbsp; 系统自动在栈中为b开辟空&nbsp;&nbsp;</span><br style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;" /><span style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;">&nbsp; 间&nbsp;&nbsp;&nbsp;&nbsp;</span><br style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;" /><span style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;">&nbsp; heap:&nbsp;&nbsp;&nbsp;&nbsp;</span><br style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;" /><span style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;">&nbsp; 需要程序员自己申请，并指明大小，在c中malloc函数&nbsp;&nbsp;&nbsp;&nbsp;</span><br style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;" /><span style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;">&nbsp; 如p1&nbsp;&nbsp; =&nbsp;&nbsp; (char&nbsp;&nbsp; *)malloc(10);&nbsp;&nbsp;&nbsp;&nbsp;</span><br style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;" /><span style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;">&nbsp; 在C++中用new运算符&nbsp;&nbsp;&nbsp;&nbsp;</span><br style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;" /><span style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;">&nbsp; 如p2&nbsp;&nbsp; =&nbsp;&nbsp; new&nbsp;&nbsp; char[10];&nbsp;&nbsp;&nbsp;&nbsp;</span><br style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;" /><span style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;">&nbsp; 但是注意p1、p2本身是在栈中的。&nbsp;&nbsp;&nbsp;&nbsp;</span><br style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;" /><span style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;">&nbsp;&nbsp;&nbsp;</span><br style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;" /><span style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;">&nbsp;&nbsp;&nbsp;</span><br style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;" /><span style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;">&nbsp; 2.2&nbsp;&nbsp;&nbsp;&nbsp;</span><br style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;" /><span style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;">&nbsp; 申请后系统的响应&nbsp;&nbsp;&nbsp;&nbsp;</span><br style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;" /><span style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;">&nbsp; 栈：只要栈的剩余空间大于所申请空间，系统将为程序提供内存，否则将报异常提示栈溢&nbsp;&nbsp;</span><br style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;" /><span style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;">&nbsp; 出。&nbsp;&nbsp;&nbsp;&nbsp;</span><br style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;" /><span style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;">&nbsp; 堆：首先应该知道操作系统有一个记录空闲内存地址的链表，当系统收到程序的申请时，&nbsp;&nbsp;</span><br style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;" /><span style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;">&nbsp; 会遍历该链表，寻找第一个空间大于所申请空间的堆结点，然后将该结点从空闲结点链表&nbsp;&nbsp;</span><br style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;" /><span style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;">&nbsp; 中删除，并将该结点的空间分配给程序，另外，对于大多数系统，会在这块内存空间中的&nbsp;&nbsp;</span><br style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;" /><span style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;">&nbsp; 首地址处记录本次分配的大小，这样，代码中的delete语句才能正确的释放本内存空间。&nbsp;&nbsp;</span><br style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;" /><span style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;">&nbsp; 另外，由于找到的堆结点的大小不一定正好等于申请的大小，系统会自动的将多余的那部&nbsp;&nbsp;</span><br style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;" /><span style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;">&nbsp; 分重新放入空闲链表中。&nbsp;&nbsp;&nbsp;&nbsp;</span><br style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;" /><span style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;">&nbsp;&nbsp;&nbsp;</span><br style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;" /><span style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;">&nbsp; 2.3申请大小的限制&nbsp;&nbsp;&nbsp;&nbsp;</span><br style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;" /><span style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;">&nbsp; 栈：在Windows下,栈是向低地址扩展的数据结构，是一块连续的内存的区域。这句话的意&nbsp;&nbsp;</span><br style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;" /><span style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;">&nbsp; 思是栈顶的地址和栈的最大容量是系统预先规定好的，在WINDOWS下，栈的大小是2M（也有&nbsp;&nbsp;</span><br style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;" /><span style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;">&nbsp; 的说是1M，总之是一个编译时就确定的常数），如果申请的空间超过栈的剩余空间时，将&nbsp;&nbsp;</span><br style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;" /><span style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;">&nbsp; 提示overflow。因此，能从栈获得的空间较小。&nbsp;&nbsp;&nbsp;&nbsp;</span><br style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;" /><span style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;">&nbsp; 堆：堆是向高地址扩展的数据结构，是不连续的内存区域。这是由于系统是用链表来存储&nbsp;&nbsp;</span><br style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;" /><span style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;">&nbsp; 的空闲内存地址的，自然是不连续的，而链表的遍历方向是由低地址向高地址。堆的大小&nbsp;&nbsp;</span><br style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;" /><span style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;">&nbsp; 受限于计算机系统中有效的虚拟内存。由此可见，堆获得的空间比较灵活，也比较大。&nbsp;&nbsp;&nbsp;&nbsp;</span><br style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;" /><span style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;">&nbsp;&nbsp;&nbsp;</span><br style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;" /><span style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;">&nbsp;&nbsp;&nbsp;</span><br style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;" /><span style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;">&nbsp;&nbsp;&nbsp;</span><br style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;" /><span style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;">&nbsp; 2.4申请效率的比较：&nbsp;&nbsp;&nbsp;&nbsp;</span><br style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;" /><span style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;">&nbsp; 栈由系统自动分配，速度较快。但程序员是无法控制的。&nbsp;&nbsp;&nbsp;&nbsp;</span><br style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;" /><span style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;">&nbsp; 堆是由new分配的内存，一般速度比较慢，而且容易产生内存碎片,不过用起来最方便.&nbsp;&nbsp;&nbsp;&nbsp;</span><br style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;" /><span style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;">&nbsp; 另外，在WINDOWS下，最好的方式是用VirtualAlloc分配内存，他不是在堆，也不是在栈是&nbsp;&nbsp;</span><br style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;" /><span style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;">&nbsp; 直接在进程的地址空间中保留一块内存，虽然用起来最不方便。但是速度快，也最灵活。&nbsp;&nbsp;</span><br style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;" /><span style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><br style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;" /><span style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;">&nbsp;&nbsp;&nbsp;</span><br style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;" /><span style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;">&nbsp; 2.5堆和栈中的存储内容&nbsp;&nbsp;&nbsp;&nbsp;</span><br style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;" /><span style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;">&nbsp; 栈：&nbsp;&nbsp; 在函数调用时，第一个进栈的是主函数中后的下一条指令（函数调用语句的下一条可&nbsp;&nbsp;</span><br style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;" /><span style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;">&nbsp; 执行语句）的地址，然后是函数的各个参数，在大多数的C编译器中，参数是由右往左入栈&nbsp;&nbsp;</span><br style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;" /><span style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;">&nbsp; 的，然后是函数中的局部变量。注意静态变量是不入栈的。&nbsp;&nbsp;&nbsp;&nbsp;</span><br style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;" /><span style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;">&nbsp; 当本次函数调用结束后，局部变量先出栈，然后是参数，最后栈顶指针指向最开始存的地&nbsp;&nbsp;</span><br style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;" /><span style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;">&nbsp; 址，也就是主函数中的下一条指令，程序由该点继续运行。&nbsp;&nbsp;&nbsp;&nbsp;</span><br style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;" /><span style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;">&nbsp; 堆：一般是在堆的头部用一个字节存放堆的大小。堆中的具体内容由程序员安排。&nbsp;&nbsp;&nbsp;&nbsp;</span><br style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;" /><span style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;">&nbsp;&nbsp;&nbsp;</span><br style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;" /><span style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;">&nbsp; 2.6存取效率的比较&nbsp;&nbsp;&nbsp;&nbsp;</span><br style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;" /><span style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;">&nbsp;&nbsp;&nbsp;</span><br style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;" /><span style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;">&nbsp; char&nbsp;&nbsp; s1[]&nbsp;&nbsp; =&nbsp;&nbsp; "aaaaaaaaaaaaaaa";&nbsp;&nbsp;&nbsp;&nbsp;</span><br style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;" /><span style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;">&nbsp; char&nbsp;&nbsp; *s2&nbsp;&nbsp; =&nbsp;&nbsp; "bbbbbbbbbbbbbbbbb";&nbsp;&nbsp;&nbsp;&nbsp;</span><br style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;" /><span style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;">&nbsp; aaaaaaaaaaa是在运行时刻赋值的；&nbsp;&nbsp;&nbsp;&nbsp;</span><br style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;" /><span style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;">&nbsp; 而bbbbbbbbbbb是在编译时就确定的；&nbsp;&nbsp;&nbsp;&nbsp;</span><br style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;" /><span style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;">&nbsp; 但是，在以后的存取中，在栈上的数组比指针所指向的字符串(例如堆)快。 &nbsp;&nbsp;<br /><br /></span><span style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;">&nbsp; 2.7小结：&nbsp;&nbsp;&nbsp;&nbsp;</span><br style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;" /><span style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;">&nbsp; 堆和栈的区别可以用如下的比喻来看出：&nbsp;&nbsp;&nbsp;&nbsp;</span><br style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;" /><span style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;">&nbsp; 使用栈就象我们去饭馆里吃饭，只管点菜（发出申请）、付钱、和吃（使用），吃饱了就&nbsp;&nbsp;</span><br style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;" /><span style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;">&nbsp; 走，不必理会切菜、洗菜等准备工作和洗碗、刷锅等扫尾工作，他的好处是快捷，但是自&nbsp;&nbsp;</span><br style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;" /><span style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;">&nbsp; 由度小。&nbsp;&nbsp;&nbsp;&nbsp;</span><br style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;" /><span style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;">&nbsp; 使用堆就象是自己动手做喜欢吃的菜肴，比较麻烦，但是比较符合自己的口味，而且自由&nbsp;&nbsp;</span><br style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;" /><span style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;">&nbsp; 度大。&nbsp;&nbsp; (经典！) &nbsp;</span><br /><img src ="http://www.cppblog.com/zhenglinbo/aggbug/203451.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/zhenglinbo/" target="_blank">hoshelly</a> 2013-09-27 09:13 <a href="http://www.cppblog.com/zhenglinbo/archive/2013/09/27/203451.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java对象引用（转）</title><link>http://www.cppblog.com/zhenglinbo/archive/2013/09/27/203450.html</link><dc:creator>hoshelly</dc:creator><author>hoshelly</author><pubDate>Fri, 27 Sep 2013 00:39:00 GMT</pubDate><guid>http://www.cppblog.com/zhenglinbo/archive/2013/09/27/203450.html</guid><wfw:comment>http://www.cppblog.com/zhenglinbo/comments/203450.html</wfw:comment><comments>http://www.cppblog.com/zhenglinbo/archive/2013/09/27/203450.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/zhenglinbo/comments/commentRss/203450.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/zhenglinbo/services/trackbacks/203450.html</trackback:ping><description><![CDATA[<div><span style="font-size: 12px;">作者：Vamei 出处：http://www.cnblogs.com/vamei 欢迎转载，也请保留这段声明。谢谢！</span></div><div><span style="font-size: 12px;"><br /></span></div><div>&nbsp;</div><div><span style="font-size: 12px;"><br /></span></div><div><span style="font-size: 12px;">我们之前一直在使用&#8220;对象&#8221;这个概念，但没有探讨对象在内存中的具体存储方式。这方面的讨论将引出&#8220;对象引用&#8221;(object reference)这一重要概念。&nbsp;</span></div><div><span style="font-size: 12px;"><br /></span></div><div>&nbsp;</div><div><span style="font-size: 12px;"><br /></span></div><div><span style="font-size: 12px;">对象引用</span></div><div><span style="font-size: 12px;">我们沿用之前定义的Human类，并有一个Test类:</span></div><div><span style="font-size: 12px;"><br /></span></div><div><span style="font-size: 12px;">复制代码</span></div><div><span style="font-size: 12px;">public class Test</span></div><div><span style="font-size: 12px;">{</span></div><div><span style="font-size: 12px;">&nbsp; &nbsp; public static void main(String[] args)</span></div><div><span style="font-size: 12px;">&nbsp; &nbsp; {</span></div><div><span style="font-size: 12px;">&nbsp; &nbsp; &nbsp; &nbsp; Human aPerson = new Human(160); &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</span></div><div><span style="font-size: 12px;">&nbsp; &nbsp; }</span></div><div><span style="font-size: 12px;">}</span></div><div><span style="font-size: 12px;"><br /></span></div><div><span style="font-size: 12px;">class Human</span></div><div><span style="font-size: 12px;">{ &nbsp;&nbsp;</span></div><div><span style="font-size: 12px;">&nbsp; &nbsp; /**</span></div><div><span style="font-size: 12px;">&nbsp; &nbsp; &nbsp;* constructor</span></div><div><span style="font-size: 12px;">&nbsp; &nbsp; &nbsp;*/</span></div><div><span style="font-size: 12px;">&nbsp; &nbsp; public Human(int h)</span></div><div><span style="font-size: 12px;">&nbsp; &nbsp; {</span></div><div><span style="font-size: 12px;">&nbsp; &nbsp; &nbsp; &nbsp; this.height = h;</span></div><div><span style="font-size: 12px;">&nbsp; &nbsp; }</span></div><div><span style="font-size: 12px;"><br /></span></div><div><span style="font-size: 12px;">&nbsp; &nbsp; /**</span></div><div><span style="font-size: 12px;">&nbsp; &nbsp; &nbsp;* accessor</span></div><div><span style="font-size: 12px;">&nbsp; &nbsp; &nbsp;*/</span></div><div><span style="font-size: 12px;">&nbsp; &nbsp; public int getHeight()</span></div><div><span style="font-size: 12px;">&nbsp; &nbsp; {</span></div><div><span style="font-size: 12px;">&nbsp; &nbsp; &nbsp; &nbsp;return this.height;</span></div><div><span style="font-size: 12px;">&nbsp; &nbsp; }</span></div><div><span style="font-size: 12px;"><br /></span></div><div><span style="font-size: 12px;">&nbsp; &nbsp; /**</span></div><div><span style="font-size: 12px;">&nbsp; &nbsp; &nbsp;* mutator</span></div><div><span style="font-size: 12px;">&nbsp; &nbsp; &nbsp;*/</span></div><div><span style="font-size: 12px;">&nbsp; &nbsp; public void growHeight(int h)</span></div><div><span style="font-size: 12px;">&nbsp; &nbsp; {</span></div><div><span style="font-size: 12px;">&nbsp; &nbsp; &nbsp; &nbsp; this.height = this.height + h;</span></div><div><span style="font-size: 12px;">&nbsp; &nbsp; }</span></div><div><span style="font-size: 12px;"><br /></span></div><div><span style="font-size: 12px;">&nbsp; &nbsp; private int height;</span></div><div><span style="font-size: 12px;">}</span></div><div><span style="font-size: 12px;">复制代码</span></div><div>&nbsp;</div><div><span style="font-size: 12px;"><br /></span></div><div><span style="font-size: 12px;">外部可以调用类来创建对象，比如上面在Test类中:</span></div><div><span style="font-size: 12px;"><br /></span></div><div><span style="font-size: 12px;">Human aPerson = new Human(160);</span></div><div><span style="font-size: 12px;">创建了一个Human类的对象aPerson。&nbsp;</span></div><div><span style="font-size: 12px;"><br /></span></div><div><span style="font-size: 12px;">上面是一个非常简单的表述，但我们有许多细节需要深入:</span></div><div><span style="font-size: 12px;"><br /></span></div><div><span style="font-size: 12px;">首先看等号的右侧。new是在内存中为对象开辟空间。具体来说，new是在内存的堆(heap)上为对象开辟空间。这一空间中，保存有对象的数据和方法。</span></div><div><span style="font-size: 12px;">再看等号的左侧。aPerson指代一个Human对象，被称为对象引用(reference)。实际上，aPerson并不是对象本身，而是类似于一个指向对象的指针。aPerson存在于内存的栈(stack)中。</span></div><div><span style="font-size: 12px;">当我们用等号赋值时，是将右侧new在堆中创建对象的地址赋予给对象引用。</span></div><div><span style="font-size: 12px;">这里的内存，指的是JVM (Java Virtual Machine)虚拟出来的Java进程内存空间。内存的堆和栈概念可参考Linux从程序到进程。</span></div><div><span style="font-size: 12px;"><br /></span></div><div>&nbsp;<img src="http://www.cppblog.com/images/cppblog_com/zhenglinbo/31232316-9ceb14006ae34b97b3fbefaafccc9f80.png" border="0" alt="" width="211" height="274" /></div><div><span style="font-size: 12px;"><br /></span></div><div><span style="font-size: 12px;"><br /></span></div><div><span style="font-size: 12px;"><br /></span></div><div><span style="font-size: 12px;">对象引用</span></div><div><span style="font-size: 12px;"><br /></span></div><div></div><div><span style="font-size: 12px;"><br /></span></div><div><span style="font-size: 12px;">栈的读取速度比堆快，但栈上存储的数据受到有效范围的限制。在C语言中，当一次函数调用结束时，相应的栈帧(stack frame)要删除，栈帧上存储的参量和自动变量就消失了。Java的栈也受到同样的限制，当一次方法调用结束，该方法存储在栈上的数据将清空。在 Java中，所有的(普通)对象都储存在堆上。因此，new关键字的完整含义是，在堆上创建对象。</span></div><div><span style="font-size: 12px;"><br /></span></div><div>&nbsp;</div><div><span style="font-size: 12px;"><br /></span></div><div><span style="font-size: 12px;">基本类型(primitive type)的对象，比如int, double，保存在栈上。当我们声明基本类型时，不需要new。一旦声明，Java将在栈上直接存储基本类型的数据。所以，基本类型的变量名表示的是数据本身，不是引用。</span></div><div><span style="font-size: 12px;"><br /></span></div><div>&nbsp;</div><div><span style="font-size: 12px;"><br /></span></div><div>&nbsp;</div><div><span style="font-size: 12px;"><br /></span></div><div><span style="font-size: 12px;">引用和对象的关系就像风筝和人。我们看天空时(程序里写的)，看到的是风筝(引用)，但风筝下面对应的，是人(对象):</span></div><div><span style="font-size: 12px;"><br /></span></div><div><span style="font-size: 12px;"><img src="http://www.cppblog.com/images/cppblog_com/zhenglinbo/2.jpg" border="0" alt="" width="600" height="776" /><br /></span></div><div><span style="font-size: 12px;"><br /></span></div><div><span style="font-size: 12px;">引用和对象分离；引用指向对象</span></div><div><span style="font-size: 12px;"><br /></span></div><div>&nbsp;</div><div><span style="font-size: 12px;"><br /></span></div><div><span style="font-size: 12px;">尽管引用和对象是分离的，但我们所有通往对象的访问必须经过引用这个&#8220;大门&#8221;，比如以 引用.方法() 的方式访问对象的方法。在Java中，我们不能跳过引用去直接接触对象。再比如，对象a的数据成员如果是一个普通对象b，a的数据成员保存的是指向对象b的引用 (如果是基本类型变量，那么a的数据成员保存的是基本类型变量本身了)。</span></div><div><span style="font-size: 12px;"><br /></span></div><div><span style="font-size: 12px;">在Java中，引用起到了指针的作用，但我们不能直接修改指针的值，比如像C语言那样将指针值加1。我们只能通过引用执行对对象的操作。这样的设计避免了许多指针可能引起的错误。</span></div><div><span style="font-size: 12px;"><br /></span></div><div>&nbsp;</div><div><span style="font-size: 12px;"><br /></span></div><div><span style="font-size: 12px;">引用的赋值</span></div><div><span style="font-size: 12px;">当我们将一个引用赋值给另一个引用时，我们实际上复制的是对象的地址。两个引用将指向同一对象。比如 dummyPerson=aPerson;，将导致:</span></div><div><span style="font-size: 12px;"><br /></span></div><div><span style="font-size: 12px;"><img src="http://www.cppblog.com/images/cppblog_com/zhenglinbo/3.png" border="0" alt="" width="279" height="318" /><br /></span></div><div><span style="font-size: 12px;"><br /></span></div><div><span style="font-size: 12px;">一个对象可以有多个引用 (一个人可以放多个风筝)。当程序通过某个引用修改对象时，通过其他引用也可以看到该修改。我们可以用以下Test类来测试实际效果:</span></div><div><span style="font-size: 12px;"><br /></span></div><div><span style="font-size: 12px;">复制代码</span></div><div><span style="font-size: 12px;">public class Test</span></div><div><span style="font-size: 12px;">{</span></div><div><span style="font-size: 12px;">&nbsp; &nbsp; public static void main(String[] args)</span></div><div><span style="font-size: 12px;">&nbsp; &nbsp; &nbsp; &nbsp; {</span></div><div><span style="font-size: 12px;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Human aPerson = new Human(160);</span></div><div><span style="font-size: 12px;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Human dummyPerson = aPerson;</span></div><div><span style="font-size: 12px;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;System.out.println(dummyPerson.getHeight());</span></div><div><span style="font-size: 12px;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;aPerson.growHeight(20);</span></div><div><span style="font-size: 12px;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;System.out.println(dummyPerson.getHeight());</span></div><div><span style="font-size: 12px;">&nbsp; &nbsp; &nbsp; &nbsp; }</span></div><div><span style="font-size: 12px;">}</span></div><div><span style="font-size: 12px;">复制代码</span></div><div><span style="font-size: 12px;">我们对aPerson的修改将影响到dummyPerson。这两个引用实际上指向同一对象。</span></div><div><span style="font-size: 12px;"><br /></span></div><div>&nbsp;</div><div><span style="font-size: 12px;"><br /></span></div><div><span style="font-size: 12px;">所以，将一个引用赋值给另一个引用，并不能复制对象本身。我们必须寻求其他的机制来复制对象。</span></div><div><span style="font-size: 12px;"><br /></span></div><div>&nbsp;</div><div><span style="font-size: 12px;"><br /></span></div><div><span style="font-size: 12px;">垃圾回收</span></div><div><span style="font-size: 12px;">随着方法调用的结束，引用和基本类型变量会被清空。由于对象存活于堆，所以对象所占据的内存不会随着方法调用的结束而清空。进程空间可能很快被不断创建的对象占满。Java内建有垃圾回收(garbage collection)机制，用于清空不再使用的对象，以回收内存空间。</span></div><div><span style="font-size: 12px;"><br /></span></div><div><span style="font-size: 12px;">垃圾回收的基本原则是，当存在引用指向某个对象时，那么该对象不会被回收; 当没有任何引用指向某个对象时，该对象被清空。它所占据的空间被回收。</span></div><div><span style="font-size: 12px;"><img src="http://www.cppblog.com/images/cppblog_com/zhenglinbo/4.png" border="0" alt="" width="307" height="464" /><br /></span></div><div><span style="font-size: 12px;">上图假设了某个时刻JVM中的内存状态。Human Object有三个引用: 来自栈的aPerson和dummyPerson，以及另一个对象的数据成员president。而Club Object没有引用。如果这个时候垃圾回收启动，那么Club Object将被清空，而Human Object来自Club Object的引用(president)也随之被删除。</span></div><div><span style="font-size: 12px;"><br /></span></div><div>&nbsp;</div><div><span style="font-size: 12px;"><br /></span></div><div><span style="font-size: 12px;">垃圾回收是Java中重要的机制，它直接影响了Java的运行效率。我将在以后深入其细节。</span></div><div><span style="font-size: 12px;"><br /></span></div><div>&nbsp;</div><div><span style="font-size: 12px;"><br /></span></div><div><span style="font-size: 12px;">参数传递<br /><br /></span></div><div><span style="font-size: 12px;">当我们分离了引用和对象的概念后，Java方法的参数传递机制实际上非常清晰: Java的参数传递为值传递。也就是说，当我们传递一个参数时，方法将获得该参数的一个拷贝。</span></div><div><span style="font-size: 12px;"><br /></span></div><div><span style="font-size: 12px;">实际上，我们传递的参数，一个是基本类型的变量，另一个为对象的引用。</span></div><div><span style="font-size: 12px;"><br /></span></div><div><span style="font-size: 12px;">基本类型变量的值传递，意味着变量本身被复制，并传递给Java方法。Java方法对变量的修改不会影响到原变量。</span></div><div><span style="font-size: 12px;"><br /></span></div><div><span style="font-size: 12px;">引用的值传递，意味着对象的地址被复制，并传递给Java方法。Java方法根据该引用的访问将会影响对象。</span></div><div><span style="font-size: 12px;"><br /></span></div><div>&nbsp;</div><div><span style="font-size: 12px;"><br /></span></div><div><span style="font-size: 12px;">在这里有另一个值得一提的情况: 我们在方法内部使用new创建对象，并将该对象的引用返回。如果该返回被一个引用接收，由于对象的引用不为0，对象依然存在，不会被垃圾回收。</span></div><div><span style="font-size: 12px;"><br /></span></div><div>&nbsp;</div><div><span style="font-size: 12px;"><br /></span></div><div><span style="font-size: 12px;">总结</span></div><div><span style="font-size: 12px;">new</span></div><div><span style="font-size: 12px;"><br /></span></div><div><span style="font-size: 12px;">引用，对象</span></div><div><span style="font-size: 12px;"><br /></span></div><div><span style="font-size: 12px;">被垃圾回收的条件</span></div><div><span style="font-size: 12px;"><br /></span></div><div><span style="font-size: 12px;">参数: 值传递</span></div><div><span style="font-size: 12px;"><br /></span></div><div>&nbsp;</div><img src ="http://www.cppblog.com/zhenglinbo/aggbug/203450.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/zhenglinbo/" target="_blank">hoshelly</a> 2013-09-27 08:39 <a href="http://www.cppblog.com/zhenglinbo/archive/2013/09/27/203450.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java socket编程入门（转）</title><link>http://www.cppblog.com/zhenglinbo/archive/2013/07/05/201533.html</link><dc:creator>hoshelly</dc:creator><author>hoshelly</author><pubDate>Fri, 05 Jul 2013 07:55:00 GMT</pubDate><guid>http://www.cppblog.com/zhenglinbo/archive/2013/07/05/201533.html</guid><wfw:comment>http://www.cppblog.com/zhenglinbo/comments/201533.html</wfw:comment><comments>http://www.cppblog.com/zhenglinbo/archive/2013/07/05/201533.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/zhenglinbo/comments/commentRss/201533.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/zhenglinbo/services/trackbacks/201533.html</trackback:ping><description><![CDATA[这个网站上讲得很清楚，就不转载了，直接贴地址：<span style="font-size: 12px;"><a href="http://www.binarytides.com/java-socket-programming-tutorial/">http://www.binarytides.com/java-socket-programming-tutorial/</a></span><img src ="http://www.cppblog.com/zhenglinbo/aggbug/201533.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/zhenglinbo/" target="_blank">hoshelly</a> 2013-07-05 15:55 <a href="http://www.cppblog.com/zhenglinbo/archive/2013/07/05/201533.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>exec函数</title><link>http://www.cppblog.com/zhenglinbo/archive/2013/05/14/200259.html</link><dc:creator>hoshelly</dc:creator><author>hoshelly</author><pubDate>Tue, 14 May 2013 09:37:00 GMT</pubDate><guid>http://www.cppblog.com/zhenglinbo/archive/2013/05/14/200259.html</guid><wfw:comment>http://www.cppblog.com/zhenglinbo/comments/200259.html</wfw:comment><comments>http://www.cppblog.com/zhenglinbo/archive/2013/05/14/200259.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/zhenglinbo/comments/commentRss/200259.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/zhenglinbo/services/trackbacks/200259.html</trackback:ping><description><![CDATA[<div><span style="font-size: 10pt;">用f o r k函数创建子进程后，子进程往往要调用一种e x e c函数以执行另一个程序。</span><span style="font-size: 10pt;">当进程调用一种e x e c函数时，该进程完全由新程序代换，而新程序则从其 m a i n函数开始执行。</span><span style="font-size: 10pt;">因为调用e x e c并不创建新进程，所以前后的进程I D并未改变。</span><span style="font-size: 10pt; color: red;"><u>e x e c只是用另一个新程序替换了</u></span><span style="font-size: 10pt; color: red;"><u>当前进程的正文、数据、堆和栈段。</u></span></div><div><span style="font-size: 10pt;">有六种不同的e x e c函数可供使用（具体参考APUE），它们常常被统称为e x e c函数。这些e x e c函数都是U N I X进</span><span style="font-size: 10pt;">程控制原语。用f o r k可以创建新进程，用e x e c可以执行新的程序。e x i t函数和两个w a i t函数处理</span><span style="font-size: 10pt;">终止和等待终止。这些是我们需要的基本的进程控制原语。<br /><br /></span></div><img src ="http://www.cppblog.com/zhenglinbo/aggbug/200259.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/zhenglinbo/" target="_blank">hoshelly</a> 2013-05-14 17:37 <a href="http://www.cppblog.com/zhenglinbo/archive/2013/05/14/200259.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>init进程 与僵尸进程</title><link>http://www.cppblog.com/zhenglinbo/archive/2013/05/14/200258.html</link><dc:creator>hoshelly</dc:creator><author>hoshelly</author><pubDate>Tue, 14 May 2013 09:32:00 GMT</pubDate><guid>http://www.cppblog.com/zhenglinbo/archive/2013/05/14/200258.html</guid><wfw:comment>http://www.cppblog.com/zhenglinbo/comments/200258.html</wfw:comment><comments>http://www.cppblog.com/zhenglinbo/archive/2013/05/14/200258.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/zhenglinbo/comments/commentRss/200258.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/zhenglinbo/services/trackbacks/200258.html</trackback:ping><description><![CDATA[<div></div><div><span style="font-size: 10pt;">在说明f o r k函数时，一定是一个父进程生成一个子进程。上面又说明了子进程将其终止状</span><span style="font-size: 10pt;">态返回给父进程。但是如果父进程在子进程之前终止，则将如何呢？其回答是对于其父进程已</span><span style="font-size: 10pt;">经终止的所有进程，它们的父进程都改变为i n i t进程。</span></div><div><span style="font-size: 10pt;">我们称这些进程由i n i t进程领养。其操作</span><span style="font-size: 10pt;">过程大致是：在一个进程终止时，内核逐个检查所有活动进程，以判断它是否是正要终止的进</span><span style="font-size: 10pt;">程的子进程，如果是，则该进程的父进程I D就更改为1 ( i n i t进程的I D )。这种处理方法保证了每</span><span style="font-size: 10pt;">个进程有一个父进程。<br /><br /></span><div><span style="font-size: 10pt;">如果子进程在父进程之前终止，那么父进程又如何能在做相应检</span><span style="font-size: 10pt;">查时得到子进程的终止状态呢？对此问题的回答是内核为每个终止子进程保存了一定量的信</span></div><div><span style="font-size: 10pt;">息，所以当终止进程的父进程调用 w a i t或waitpid 时，可以得到有关信息。这种信息至少包括</span><span style="font-size: 10pt;">进程I D、该进程的终止状态、以反该进程使用的 C P U时间总量。内核可以释放终止进程所使</span><span style="font-size: 10pt;">用的所有存储器，关闭其所有打开文件。在 U N I X术语中，一个已经终止、但是其父进程尚未</span><span style="font-size: 10pt;">对其进行善后处理（获取终止子进程的有关信息、释放它仍占用的资源）的进程被称为僵死进程（z o m b i e）。p s ( 1 )命令将僵死进程的状态打印为 Z。<br /><br /></span><div><span style="font-size: 10pt;">一个由i n i t进程领养的进程终止时会发生什么?它会不会变成一</span><span style="font-size: 10pt;">个僵死进程？对此问题的回答是&#8220;否&#8221;，因为i n i t被编写成只要有一个子进程终止， i n i t就会调</span><span style="font-size: 10pt;">用一个w a i t函数取得其终止状态。这样也就防止了在系统中有很多僵死进程。当提及&#8220;一个i n i t</span><span style="font-size: 10pt;">的子进程&#8221;时，这指的是i n i t直接产生的进程，或者是其父</span><span style="font-size: 10pt;">进程已终止，由init 领养的进程。</span></div></div></div><img src ="http://www.cppblog.com/zhenglinbo/aggbug/200258.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/zhenglinbo/" target="_blank">hoshelly</a> 2013-05-14 17:32 <a href="http://www.cppblog.com/zhenglinbo/archive/2013/05/14/200258.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>fork 和 vfork 的区别 &amp; exit 和_exit的区别</title><link>http://www.cppblog.com/zhenglinbo/archive/2013/05/14/200257.html</link><dc:creator>hoshelly</dc:creator><author>hoshelly</author><pubDate>Tue, 14 May 2013 09:26:00 GMT</pubDate><guid>http://www.cppblog.com/zhenglinbo/archive/2013/05/14/200257.html</guid><wfw:comment>http://www.cppblog.com/zhenglinbo/comments/200257.html</wfw:comment><comments>http://www.cppblog.com/zhenglinbo/archive/2013/05/14/200257.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/zhenglinbo/comments/commentRss/200257.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/zhenglinbo/services/trackbacks/200257.html</trackback:ping><description><![CDATA[<span style="font-size: 10pt;">1.1<br />fork可以创建一个新的子进程，调用一次，返回两次，一次返回0值给子进程，另一次返回新的子进程的ID给父进程 。子进程是父进程的复制品，拥有父进程的数据空间、堆和栈，父子进程并不共享存储空间，如果正文段是只读的，那么父子进程共享正文段。</span><br /><span style="font-size: 10pt;">一般而言，fork之后是父进程先执行还是子进程先执行是不确定的，这取决于内核的调度算法。</span><br /><span style="font-size: 10pt;">fork有两种用法：</span><br /><span style="font-size: 10pt;">（1）一个父进程希望复制自己，使父、子进程同时执行不同的代码段。</span><span style="font-size: 10pt;">这在网络服务进程</span><span style="font-size: 10pt;">中是常见的&#8212;&#8212;父进程等待委托者的服务请求。当这种请求到达时，父进程调用 f o r k，使子进</span><span style="font-size: 10pt;">程处理此请求。父进程则继续等待下一个服务请求。</span><div><span style="font-size: 10pt;">（2） 一个进程要执行一个不同的程序。这对s h e l l是常见的情况。在这种情况下，子进程在</span><span style="font-size: 10pt;">从f o r k返回后立即调用e x e c。</span></div><br /><span style="font-size: 10pt;">1.2<br />vfork用于创建一个新的进程，而新的进程的目的就是exec一个新程序，vfork并不将父进程的地址空间复制给子进程，因为子进程会立即调用exec（_exit），于是也就不会访问地址空间。不过它在调用exec或_exit之前，它在父进程的空间中运行。<br /><br />fork创建的子进程共享父进程的数据段、堆栈段；vfork创建的子进程共享父进程的数据段。<br /><br />vfork与fork的另一个区别是：vfork保证子进程先运行，在它调用exec或exit之后父进程才可能被调度运行，（如果在调用这两个函数之前子进程依赖于父进程的进一步动作，则会导致死锁）。<br /><br />2.1<br />exit和_exit都是正常终止进程，_exit用于vfork时父进程有可能会被调度，它们都不同于异常终止abort，在异常终止情况下，内核（不是进程）产生一个指示其终止异常终止原因的终止状态。</span><img src ="http://www.cppblog.com/zhenglinbo/aggbug/200257.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/zhenglinbo/" target="_blank">hoshelly</a> 2013-05-14 17:26 <a href="http://www.cppblog.com/zhenglinbo/archive/2013/05/14/200257.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>ourhdr.h编译错误时解决办法</title><link>http://www.cppblog.com/zhenglinbo/archive/2013/05/14/200253.html</link><dc:creator>hoshelly</dc:creator><author>hoshelly</author><pubDate>Tue, 14 May 2013 08:03:00 GMT</pubDate><guid>http://www.cppblog.com/zhenglinbo/archive/2013/05/14/200253.html</guid><wfw:comment>http://www.cppblog.com/zhenglinbo/comments/200253.html</wfw:comment><comments>http://www.cppblog.com/zhenglinbo/archive/2013/05/14/200253.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/zhenglinbo/comments/commentRss/200253.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/zhenglinbo/services/trackbacks/200253.html</trackback:ping><description><![CDATA[网上找的，摘抄如下：<br /><br /><div><span style="font-size: 12px;">＃include "apue.h"</span></div><div><span style="font-size: 12px;">&nbsp; &nbsp; 这个头文件是作者把每个例程中常用的标准头文件，一些常用的出错处理函数（err_**（）之类的函</span></div><div><span style="font-size: 12px;">数）和一些常用的宏定义给整理在一个头文件中。这个可以省去在每个例程中录入较多的重复代码，这样可</span></div><div><span style="font-size: 12px;">以减少每个例程的长度。但给读者带来了不少麻烦。下面给出源代码的编译方法。</span></div><div><span style="font-size: 12px;"><br /></span></div><div>&nbsp;</div><div><span style="font-size: 12px;"><br /></span></div><div><span style="font-size: 12px;">一：整体编译：</span></div><div><span style="font-size: 12px;"><br /></span></div><div><span style="font-size: 12px;">1.APUE2源代码下载：http://www.apuebook.com/src.tar.gz</span></div><div><span style="font-size: 12px;">2.我保存到了/home/wx下.解压缩:tar zxvf src.tar.gz</span></div><div><span style="font-size: 12px;">3.cd apue.2e到apue.2e目录（查看README,告诉我们linux系统只要修改Make.defines.linux再make）</span></div><div><span style="font-size: 12px;">4.vi Make.defines.linux 修改WKDIR=/home/wx/apue.2e 就是说工作目录为WKDIR=/home/wx/apue.2e</span></div><div><span style="font-size: 12px;">5.修改/home/wx/apue.2e/std/linux.mk把全部的nawk改为awk.因些linux默认没有nawk</span></div><div><span style="font-size: 12px;">6.cd /home/wx/apue.2e</span></div><div><span style="font-size: 12px;"><br /></span></div><div><span style="font-size: 12px;">&nbsp; &nbsp;make</span></div><div><span style="font-size: 12px;">7.把生成的apue.2e/lib/libapue.a与apue.2e/include/apue.h拷贝到你编写的源代码目录下。</span></div><div><span style="font-size: 12px;"><br /></span></div><div><span style="font-size: 12px;">&nbsp; &nbsp;（注：你可以把libapue.a和apue.h保存在容易找到的文件夹中，以便使用）</span></div><div><span style="font-size: 12px;"><br /></span></div><div><span style="font-size: 12px;">8.使用gcc -o ls1 ls1.c &nbsp;libapue.a来编译你的源代码</span></div><div><span style="font-size: 12px;">9.成功<br /><br /><br /></span></div><div style="font-family: Tahoma; font-size: 11px;"></div><img src ="http://www.cppblog.com/zhenglinbo/aggbug/200253.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/zhenglinbo/" target="_blank">hoshelly</a> 2013-05-14 16:03 <a href="http://www.cppblog.com/zhenglinbo/archive/2013/05/14/200253.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Vim文本的选择</title><link>http://www.cppblog.com/zhenglinbo/archive/2013/04/13/199417.html</link><dc:creator>hoshelly</dc:creator><author>hoshelly</author><pubDate>Sat, 13 Apr 2013 14:57:00 GMT</pubDate><guid>http://www.cppblog.com/zhenglinbo/archive/2013/04/13/199417.html</guid><wfw:comment>http://www.cppblog.com/zhenglinbo/comments/199417.html</wfw:comment><comments>http://www.cppblog.com/zhenglinbo/archive/2013/04/13/199417.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/zhenglinbo/comments/commentRss/199417.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/zhenglinbo/services/trackbacks/199417.html</trackback:ping><description><![CDATA[<div><span style="font-size: 12px;"><br /></span></div><div><span style="font-size: 12px;">在正常模式下（按ESC进入）按键v进入可视化模式，然后按键盘左右键或h,l键即可实现文本的选择。</span></div><div><span style="font-size: 12px;">其它相关命令：</span></div><div><span style="font-size: 12px;">v：按字符选择。经常使用的模式，所以亲自尝试一下它。</span></div><div><span style="font-size: 12px;">V：按行选择。这在你想拷贝或者移动很多行的文本的时候特别有用。</span></div><div><span style="font-size: 12px;"><br /></span></div><div><span style="font-size: 12px;">CTRL＋v：按块选择。非常强大，只在很少的编辑器中才有这样的功能。你可以选择一个矩形块，并且在这个矩形里面的文本会被高亮。</span></div><div><span style="font-size: 12px;"><br /></span></div><div><span style="font-size: 12px;">值得注意的是如果VIM中使用自动换行，那么直到你按ENTER换行前，VIM都会将你之前输入的内容视为一行而不是你看到的好几行，按块选择时就会按VIM中的行来选择块。</span></div><div><span style="font-size: 12px;"><br /></span></div><div><span style="font-size: 12px;">在选择模式的时候使用上面所述的方向键和命令（motion）。比如，vwww，会高亮光标前面的三个词。Vjj 将会高亮当前行以及下面两行。</span></div><img src ="http://www.cppblog.com/zhenglinbo/aggbug/199417.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/zhenglinbo/" target="_blank">hoshelly</a> 2013-04-13 22:57 <a href="http://www.cppblog.com/zhenglinbo/archive/2013/04/13/199417.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>wait 和waitpid详解</title><link>http://www.cppblog.com/zhenglinbo/archive/2013/04/13/199412.html</link><dc:creator>hoshelly</dc:creator><author>hoshelly</author><pubDate>Sat, 13 Apr 2013 14:05:00 GMT</pubDate><guid>http://www.cppblog.com/zhenglinbo/archive/2013/04/13/199412.html</guid><wfw:comment>http://www.cppblog.com/zhenglinbo/comments/199412.html</wfw:comment><comments>http://www.cppblog.com/zhenglinbo/archive/2013/04/13/199412.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/zhenglinbo/comments/commentRss/199412.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/zhenglinbo/services/trackbacks/199412.html</trackback:ping><description><![CDATA[<div><span style="font-size: 12px;">wait的函数原型是： 　</span></div><div><span style="font-size: 12px;">#include&lt;sys/types.h&gt;</span></div><div><span style="font-size: 12px;">#include &lt;sys/wait.h&gt;</span></div><div><span style="font-size: 12px;"><br /></span></div><div><span style="font-size: 12px;">pid_t wait(int *status) 　　　　</span></div><div><span style="font-size: 12px;">&nbsp; &nbsp; &nbsp; 进程一旦调用了wait，就立即阻塞自己，由wait自动分析是</span></div><div><span style="font-size: 12px;">否当前进程的某个子进程已经退出，如果让它找到了这样一个</span></div><div><span style="font-size: 12px;">已经变成僵尸的子进程， wait就会收集这个子进程的信息，并</span></div><div><span style="font-size: 12px;">把它彻底销毁后返回；如果没有找到这样一个子进程，wait就</span></div><div><span style="font-size: 12px;">会一直阻塞在这里，直到有一个出现为止。　　　　</span></div><div><span style="font-size: 12px;">&nbsp; &nbsp; &nbsp; 参数status用来保存被收集进程退出时的一些状态，它是</span></div><div><span style="font-size: 12px;">一个指向int类型的指针。但如果我们对这个子进程是如何死掉</span></div><div><span style="font-size: 12px;">的毫不在意，只想把这个僵尸进程消灭掉，（事实上绝大多数</span></div><div><span style="font-size: 12px;">情况下，我们都会这样想），我们就可以设定这个参数为</span></div><div><span style="font-size: 12px;">NULL，就象下面这样：　　 　　pid = wait(NULL);</span></div><div><span style="font-size: 12px;">如果成功，wait会返回被收集的子进程的进程ID，如果调用进</span></div><div><span style="font-size: 12px;">程没有子进程，调用就会失败，此时wait返回-1，同时errno被</span></div><div><span style="font-size: 12px;">置为ECHILD。　</span></div><div><span style="font-size: 12px;">&nbsp; &nbsp; &nbsp; waitpid的函数原型是： 　　</span></div><div><span style="font-size: 12px;">waitpid系统调用在Linux函数库中的原型是： 　　</span></div><div><span style="font-size: 12px;">#include &lt;sys/types.h&gt;#include &lt;sys/wait.h&gt;</span></div><div><span style="font-size: 12px;"><br /></span></div><div><span style="font-size: 12px;">pid_t waitpid(pid_t pid,int *status,int options)</span></div><div><span style="font-size: 12px;">&nbsp; &nbsp; &nbsp; 从本质上讲，系统调用waitpid和wait的作用是完全相同</span></div><div><span style="font-size: 12px;">的，但waitpid多出了两个可由用户控制的参数pid和options，</span></div><div><span style="font-size: 12px;">从而为我们编程提供了另一种更灵活的方式。</span></div><div><span style="font-size: 12px;">下面我们就来详细介绍一下这两个参数：　　 　　</span></div><div><span style="font-size: 12px;">&#9679; pid 　　　　从参数的名字pid和类型pid_t中就可以看出，</span></div><div><span style="font-size: 12px;">这里需要的是一个进程ID。但当pid取不同的值时，在这里有不</span></div><div><span style="font-size: 12px;">同的意义。 　　　　pid&gt;0时，只等待进程ID等于pid的子进</span></div><div><span style="font-size: 12px;">程，不管其它已经有多少子进程运行结束退出了，只要指定的</span></div><div><span style="font-size: 12px;">子进程还没有结束，waitpid就会一直等下去。　　 　　pid=-</span></div><div><span style="font-size: 12px;">1时，等待任何一个子进程退出，没有任何限制，此时waitpid</span></div><div><span style="font-size: 12px;">和wait的作用一模一样。 　　　　pid=0时，等待同一个进程</span></div><div><span style="font-size: 12px;">组中的任何子进程，如果子进程已经加入了别的进程组，</span></div><div><span style="font-size: 12px;">waitpid不会对它做任何理睬。 　　　　pid&lt;-1时，等待一个</span></div><div><span style="font-size: 12px;">指定进程组中的任何子进程，这个进程组的ID等于pid的绝对</span></div><div><span style="font-size: 12px;">值。 　　</span></div><div><span style="font-size: 12px;">&#9679; options 　　options提供了一些额外的选项来控制waitpid，</span></div><div><span style="font-size: 12px;">目前在Linux中只支持WNOHANG和WUNTRACED两个选项，</span></div><div><span style="font-size: 12px;">这是两个常数，可以用"|"运算符把它们连接起来使用，比如：</span></div><div><span style="font-size: 12px;">　　ret=waitpid(-1,NULL,WNOHANG | WUNTRACED); 　　</span></div><div><span style="font-size: 12px;">如果我们不想使用它们，也可以把options设为0，如： 　　</span></div><div><span style="font-size: 12px;">ret=waitpid(-1,NULL,0); 　　　　如果使用了WNOHANG参数</span></div><div><span style="font-size: 12px;">调用waitpid，即使没有子进程退出，它也会立即返回，不会像</span></div><div><span style="font-size: 12px;">wait那样永远等下去。 　　　　而WUNTRACED参数，由于</span></div><div><span style="font-size: 12px;">涉及到一些跟踪调试方面的知识，加之极少用到，这里就不多</span></div><div><span style="font-size: 12px;">费笔墨了，有兴趣的读者可以自行查阅相关材料。　　　　看</span></div><div><span style="font-size: 12px;">到这里，聪明的读者可能已经看出端倪了--wait不就是经过包装</span></div><div><span style="font-size: 12px;">的waitpid吗？没错，察看&lt;内核源码目录&gt;/include/unistd.h文</span></div><div><span style="font-size: 12px;">件349-352行就会发现以下程序段：　　 　　static inline</span></div><div><span style="font-size: 12px;">pid_t wait(int * wait_stat) 　　{ 　　 return waitpid(-</span></div><div><span style="font-size: 12px;">1,wait_stat,0); 　　} 　　 　　返回值和错误 　　　　</span></div><div><span style="font-size: 12px;">waitpid的返回值比wait稍微复杂一些，一共有3种情况： 　</span></div><div><span style="font-size: 12px;">&#9679; 当正常返回的时候，waitpid返回收集到的子进程的进程ID；</span></div><div><span style="font-size: 12px;">&#9679; 如果设置了选项WNOHANG，而调用中waitpid发现没有已</span></div><div><span style="font-size: 12px;">退出的子进程可收集，则返回0； 　　 　　</span></div><div><span style="font-size: 12px;">&#9679; 如果调用中出错，则返回-1，这时errno会被设置成相应的</span></div><div><span style="font-size: 12px;">值以指示错误所在；当pid所指示的子进程不存在，或此进程存</span></div><div><span style="font-size: 12px;">在，但不是调用进程的子进程，waitpid就会出错返回，这时</span></div><div><span style="font-size: 12px;">errno被设置为ECHILD 其它： 调用 wait＆waitpid 来处理终止</span></div><div><span style="font-size: 12px;">的子进程： pid_t wait(int * statloc); pid_t waitpid(pid_t pid,</span></div><div><span style="font-size: 12px;">int *statloc, int options); 两个函数都返回两个值：函数的返回</span></div><div><span style="font-size: 12px;">值和终止的子进程ID，而子进程终止的状态则是通过statloc指</span></div><div><span style="font-size: 12px;">针返回的。 wait＆waitpid 的区别是显而易见的，wait等待第一</span></div><div><span style="font-size: 12px;">个终止的子进程，而waitpid则可以指定等待特定的子进程。这</span></div><div><span style="font-size: 12px;">样的区别可能会在下面这种情况时表现得更加明显：当同时有</span></div><div><span style="font-size: 12px;">5个客户连上服务器，也就是说有五个子进程分别对应了5个客</span></div><div><span style="font-size: 12px;">户，此时，五个客户几乎在同时请求终止，这样一来，几乎同</span></div><div><span style="font-size: 12px;">时，五个FIN发向服务器，同样的，五个SIGCHLD信号到达服</span></div><div><span style="font-size: 12px;">务器，然而，UNIX的信号往往是不会排队的，显然这样一来，</span></div><div><span style="font-size: 12px;">信号处理函数将只会执行一次，残留剩余四个子进程作为僵尸</span></div><div><span style="font-size: 12px;">进程驻留在内核空间。此时，正确的解决办法是利用waitpid(-</span></div><div><span style="font-size: 12px;">1, &amp;stat, WNOHANG)防止留下僵尸进程。其中的pid为－1表</span></div><div><span style="font-size: 12px;">明等待第一个终止的子进程，而WNOHANG选择项通知内核在</span></div><div><span style="font-size: 12px;">没有已终止进程项时不要阻塞。</span></div><div><span style="font-size: 12px;">wait＆waitpid 区别 :</span></div><div><span style="font-size: 12px;">waitpid提供了wait函数不能实现的3个功能: waitpid等待特定的</span></div><div><span style="font-size: 12px;">子进程, 而wait则返回任一终止状态的子进程; waitpid提供了一</span></div><div><span style="font-size: 12px;">个wait的非阻塞版本; waitpid支持作业控制(以WUNTRACED选</span></div><div><span style="font-size: 12px;">项). 用于检查wait和waitpid两个函数返回终止状态的宏: 这两个</span></div><div><span style="font-size: 12px;">函数返回的子进程状态都保存在statloc指针中, 用以下3个宏可</span></div><div><span style="font-size: 12px;">以检查该状态: WIFEXITED(status): 若为正常终止, 则为真. 此</span></div><div><span style="font-size: 12px;">时可执行 WEXITSTATUS(status): 取子进程传送给exit或_exit</span></div><div><span style="font-size: 12px;">参数的低8位. WIFSIGNALED(status): 若为异常终止, 则为真.</span></div><div><span style="font-size: 12px;">此时可执行 WTERMSIG(status): 取使子进程终止的信号编号.</span></div><div><span style="font-size: 12px;">WIFSTOPPED(status): 若为当前暂停子进程, 则为真. 此时可</span></div><div><span style="font-size: 12px;">执行 WSTOPSIG(status): 取使子进程暂停的信号编号<br /></span></div><img src ="http://www.cppblog.com/zhenglinbo/aggbug/199412.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/zhenglinbo/" target="_blank">hoshelly</a> 2013-04-13 22:05 <a href="http://www.cppblog.com/zhenglinbo/archive/2013/04/13/199412.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>