<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Dutor &#187; 虚拟内存</title>
	<atom:link href="http://www.dutor.net/index.php/tag/vm/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.dutor.net</link>
	<description>熟读而精思，循序而渐进，厚积而薄发。</description>
	<lastBuildDate>Tue, 17 Jan 2012 14:44:19 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>reserve: 对老new的新认识</title>
		<link>http://www.dutor.net/index.php/2011/04/reserve-new-virtual-physical-memory/</link>
		<comments>http://www.dutor.net/index.php/2011/04/reserve-new-virtual-physical-memory/#comments</comments>
		<pubDate>Mon, 25 Apr 2011 13:43:16 +0000</pubDate>
		<dc:creator>dutor</dc:creator>
				<category><![CDATA[之语言特性]]></category>
		<category><![CDATA[边走编程]]></category>
		<category><![CDATA[Cpp]]></category>
		<category><![CDATA[new]]></category>
		<category><![CDATA[虚拟内存]]></category>

		<guid isPermaLink="false">http://www.dutor.net/?p=2568</guid>
		<description><![CDATA[　　reserve内部是怎么实现的呢？当然是new了。那么在reserve操作，也就是new之后，我们程序是否立即就占用了这些内存呢？这就要看我们这里说的“内存”是什么样的内存了。什么意思呢？我们知道，现代操作系统都采用了虚拟内存的机制，内存占用也就有了虚拟内存（virtual memory）和物理内存（physical memory）之分了。
　　我们又知道，Unix/Linux进程的虚拟地址空间被按用途被划分成了内核空间和用户空间。内核空间供操作系统的内核使用，用户空间供用户程序支配。其中用户空间又被划分为若干段，主要包括：代码段（.text），用来存放/映射用户程序的代码；数据段（.data），存放初始化的全局数据或静态数据，这部分在文件系统中也占据磁盘空间；.bss段（一直没找到一个亲切的翻译），存放为初始化的全局或静态数据，在程序加载时分配空间和初始化，这部分空间不占用磁盘空间（当然在可执行文件中要保留其大小）；堆栈段，用来保存程序执行时的上下文（局部变量、函数参数和返回地址等），在进程建立时由操作系统分配，空间较小且在运行时不可动态调整，增长方向因机器架构而异，IA上自高地址向下增长，堆栈不占用磁盘空间；堆，供用户在运行时动态地申请和使用，空间较大，未被申请的堆空间不可使用，也不会被映射到物理空间，堆随着用户程序申请向上增长，堆不占用磁盘空间。]]></description>
			<content:encoded><![CDATA[<p>　　C++ STL中的vector&lt;T>是一个变长“数组，在使用push_back等插入操作向vector中添加元素时可以动态地增长其容量(capacity)。然而，这种动态扩容的特性也带来了一定的性能负担。当vector当前容量不足以容纳待插入元素时，vector会另外开辟一段连续的内存，然后将原有元素拷贝(使用元素的copy构造)至新的内存区域，然后释放掉原先占据的内存，特定情况下，这可能是一笔不小的不必要的开销。vector的设计者当然也考虑到这一点，于是提供了reverve(ssize_t)成员函数。顾名思义，reserve为vector预定了一定大小的连续空间，使得在vector元素数量不超过当前容量的插入操作过程中，不会发生拷贝操作，原有迭代器、指针和引用当然也不会失效（insert类操作除外）。</p>
<p>　　reserve内部是怎么实现的呢？当然是new了。那么在reserve操作，也就是new之后，我们程序是否立即就占用了这些内存呢？这就要看我们这里说的“内存”是什么样的内存了。什么意思呢？我们知道，现代操作系统都采用了虚拟内存的机制，内存占用也就有了虚拟内存（virtual memory）和物理内存（physical memory）之分了。<br />
　　我们又知道，Unix/Linux进程的虚拟地址空间被按用途被划分成了内核空间和用户空间。内核空间供操作系统的内核使用，用户空间供用户程序支配。其中用户空间又被划分为若干段，主要包括：代码段（.text），用来存放/映射用户程序的代码；数据段（.data），存放初始化的全局数据或静态数据，这部分在文件系统中也占据磁盘空间；.bss段（一直没找到一个亲切的翻译），存放为初始化的全局或静态数据，在程序加载时分配空间和初始化，这部分空间不占用磁盘空间（当然在可执行文件中要保留其大小）；堆栈段，用来保存程序执行时的上下文（局部变量、函数参数和返回地址等），在进程建立时由操作系统分配，空间较小且在运行时不可动态调整，增长方向因机器架构而异，IA上自高地址向下增长，堆栈不占用磁盘空间；堆，供用户在运行时动态地申请和使用，空间较大，未被申请的堆空间不可使用，也不会被映射到物理空间，堆随着用户程序申请向上增长，堆不占用磁盘空间。</p>
<p>　　这么长的开场白之后，我们还知道，new负责在运行时（通过运行时库）为用户程序在堆上申请空间。但，而且，当然，new出的只是虚拟空间。在未对该空间进行读写时，这些空间并未被映射到物理空间，即操作系统还没有为这段空间分配物理内存。只有当程序开始对刚刚申请的虚拟空间进行访问时，被操作系统的虚拟内存机制觉察到（页中断）这一请求，才会为访问地址所在的虚存页面分配和映射物理页面，访问才得以进行。可以使用下面程序对此作出验证，</p>

<div class="wp_codebox"><table><tr id="p25681"><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
</pre></td><td class="code" id="p2568code1"><pre class="cpp" style="font-family:monospace;"><span style="color: #0000ff;">int</span>
main<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span>
<span style="color: #008000;">&#123;</span>
    sleep<span style="color: #008000;">&#40;</span><span style="color: #0000dd;">3</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    std<span style="color: #008080;">::</span><span style="color: #0000dd;">cout</span><span style="color: #000080;">&lt;&lt;</span><span style="color: #FF0000;">&quot;stage 1...&quot;</span><span style="color: #000080;">&lt;&lt;</span>std<span style="color: #008080;">::</span><span style="color: #007788;">endl</span><span style="color: #008080;">;</span>
    <span style="color: #0000ff;">char</span> <span style="color: #000040;">*</span>p <span style="color: #000080;">=</span> <span style="color: #0000dd;">new</span> <span style="color: #0000ff;">char</span><span style="color: #008000;">&#91;</span>1U<span style="color: #000080;">&lt;&lt;</span><span style="color: #0000dd;">30</span> <span style="color: #000040;">*</span> <span style="color: #0000dd;">2</span><span style="color: #008000;">&#93;</span><span style="color: #008080;">;</span> <span style="color: #666666;">//~ 2GB</span>
&nbsp;
    sleep<span style="color: #008000;">&#40;</span><span style="color: #0000dd;">3</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    std<span style="color: #008080;">::</span><span style="color: #0000dd;">cout</span><span style="color: #000080;">&lt;&lt;</span><span style="color: #FF0000;">&quot;stage 2...&quot;</span><span style="color: #000080;">&lt;&lt;</span>std<span style="color: #008080;">::</span><span style="color: #007788;">endl</span><span style="color: #008080;">;</span>
&nbsp;
    <span style="color: #0000ff;">for</span><span style="color: #008000;">&#40;</span><span style="color: #0000ff;">unsigned</span> i <span style="color: #000080;">=</span> <span style="color: #0000dd;">0</span><span style="color: #008080;">;</span> i <span style="color: #000080;">&lt;</span> <span style="color: #008000;">&#40;</span>1U<span style="color: #000080;">&lt;&lt;</span><span style="color: #0000dd;">30</span><span style="color: #000040;">*</span><span style="color: #0000dd;">2</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <span style="color: #000040;">++</span>i<span style="color: #008000;">&#41;</span> <span style="color: #666666;">//~ access</span>
    <span style="color: #008000;">&#123;</span>
        p<span style="color: #008000;">&#91;</span>i<span style="color: #008000;">&#93;</span> <span style="color: #000080;">=</span> <span style="color: #0000dd;">0</span><span style="color: #008080;">;</span>
        usleep<span style="color: #008000;">&#40;</span><span style="color: #0000dd;">1000</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <span style="color: #666666;">//~ per millisecond</span>
    <span style="color: #008000;">&#125;</span>
    <span style="color: #0000ff;">return</span> <span style="color: #0000dd;">0</span><span style="color: #008080;">;</span>
<span style="color: #008000;">&#125;</span></pre></td></tr></table></div>

<p>　　运行此程序，同时使用top命令观察。主要观察两项，new前后程序的虚存占用，以及stage 2中程序驻留内存（REsident Size，即物理内存）的变化。另外，为了观察方便，最好调整top命令，使其按内存占用对进程排序。</p>
<p>　　上面虽然没有介绍太多东西，但由于本人水平有限，难免会有错误及不清楚之处，如果“不幸”被你发现了，还请指出和补充之。<br />
　　关于内存管理，学习过程中总会发现“惊喜”，若要做到对内存知根知底，对内核和语言运行时库的研究是必要的。对于这些个“小惊喜”，一方面说明俺是个小菜，另一方面也预示着俺是个成长中的小菜。各位看官您见笑了;-)</p>
]]></content:encoded>
			<wfw:commentRss>http://www.dutor.net/index.php/2011/04/reserve-new-virtual-physical-memory/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Dump the Holy Girl(s)</title>
		<link>http://www.dutor.net/index.php/2010/05/dump-the-holy-girls/</link>
		<comments>http://www.dutor.net/index.php/2010/05/dump-the-holy-girls/#comments</comments>
		<pubDate>Mon, 03 May 2010 22:51:20 +0000</pubDate>
		<dc:creator>dutor</dc:creator>
				<category><![CDATA[尚未分类]]></category>
		<category><![CDATA[AVL]]></category>
		<category><![CDATA[动态链接]]></category>
		<category><![CDATA[概率论]]></category>
		<category><![CDATA[虚拟内存]]></category>

		<guid isPermaLink="false">http://www.dutor.net/?p=2228</guid>
		<description><![CDATA[<p></p>
<pre lang="bash" line="1">
$ ssh FenglinHou@Dalian
~% cd Wdir/
~/Wdir% cat dump.cpp
#inlcude <everything>
int
main()
{
    std::set<std::Girl> ().clear();
    std::ifstream lifein("~/*");
    std::ofstream lifeout("~/*");
    std::copy(std::istream_iterator<std::stuff>(lifein), 
              std::istream_iterator<std::stuff>(), 
              std::ostream_iterator<std::stuff>(lifeout, "\newday"));
    return (0);
}
~/Wdir% cat Makefile
dump:dump.cpp
    g++ -odump dump.cpp
~/Wdir% make
~/Wdir% ./dump

</pre>]]></description>
			<content:encoded><![CDATA[</p>

<div class="wp_codebox"><table><tr id="p22282"><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
</pre></td><td class="code" id="p2228code2"><pre class="bash" style="font-family:monospace;">$ <span style="color: #c20cb9; font-weight: bold;">ssh</span> FenglinHou<span style="color: #000000; font-weight: bold;">@</span>Dalian
~<span style="color: #000000; font-weight: bold;">%</span> <span style="color: #7a0874; font-weight: bold;">cd</span> Wdir<span style="color: #000000; font-weight: bold;">/</span>
~<span style="color: #000000; font-weight: bold;">/</span>Wdir<span style="color: #000000; font-weight: bold;">%</span> <span style="color: #c20cb9; font-weight: bold;">cat</span> dump.cpp
<span style="color: #666666; font-style: italic;">#inlcude &lt;everything&gt;</span>
int
main<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>
<span style="color: #7a0874; font-weight: bold;">&#123;</span>
    std::<span style="color: #000000; font-weight: bold;">set</span><span style="color: #000000; font-weight: bold;">&lt;</span>std::Girl<span style="color: #000000; font-weight: bold;">&gt;</span> <span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>.clear<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>;
    std::ifstream lifein<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #ff0000;">&quot;~/*&quot;</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>;
    std::ofstream lifeout<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #ff0000;">&quot;~/*&quot;</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>;
    std::copy<span style="color: #7a0874; font-weight: bold;">&#40;</span>std::istream_iterator<span style="color: #000000; font-weight: bold;">&lt;</span>std::stuff<span style="color: #000000; font-weight: bold;">&gt;</span><span style="color: #7a0874; font-weight: bold;">&#40;</span>lifein<span style="color: #7a0874; font-weight: bold;">&#41;</span>, 
              std::istream_iterator<span style="color: #000000; font-weight: bold;">&lt;</span>std::stuff<span style="color: #000000; font-weight: bold;">&gt;</span><span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>, 
              std::ostream_iterator<span style="color: #000000; font-weight: bold;">&lt;</span>std::stuff<span style="color: #000000; font-weight: bold;">&gt;</span><span style="color: #7a0874; font-weight: bold;">&#40;</span>lifeout, <span style="color: #ff0000;">&quot;<span style="color: #000099; font-weight: bold;">\n</span>ewday&quot;</span><span style="color: #7a0874; font-weight: bold;">&#41;</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>;
    <span style="color: #7a0874; font-weight: bold;">return</span> <span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #000000;">0</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>;
<span style="color: #7a0874; font-weight: bold;">&#125;</span>
~<span style="color: #000000; font-weight: bold;">/</span>Wdir<span style="color: #000000; font-weight: bold;">%</span> <span style="color: #c20cb9; font-weight: bold;">cat</span> Makefile
dump:dump.cpp
    <span style="color: #c20cb9; font-weight: bold;">g++</span> <span style="color: #660033;">-odump</span> dump.cpp
~<span style="color: #000000; font-weight: bold;">/</span>Wdir<span style="color: #000000; font-weight: bold;">%</span> <span style="color: #c20cb9; font-weight: bold;">make</span>
~<span style="color: #000000; font-weight: bold;">/</span>Wdir<span style="color: #000000; font-weight: bold;">%</span> .<span style="color: #000000; font-weight: bold;">/</span>dump</pre></td></tr></table></div>

]]></content:encoded>
			<wfw:commentRss>http://www.dutor.net/index.php/2010/05/dump-the-holy-girls/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>虚拟内存管理总结</title>
		<link>http://www.dutor.net/index.php/2010/04/virtual-memory/</link>
		<comments>http://www.dutor.net/index.php/2010/04/virtual-memory/#comments</comments>
		<pubDate>Sun, 11 Apr 2010 05:32:48 +0000</pubDate>
		<dc:creator>dutor</dc:creator>
				<category><![CDATA[Unix/Linux]]></category>
		<category><![CDATA[OS基础]]></category>
		<category><![CDATA[虚拟内存]]></category>

		<guid isPermaLink="false">http://www.dutor.net/index.php/2010/04/%e8%99%9a%e6%8b%9f%e5%86%85%e5%ad%98%e7%ae%a1%e7%90%86%e6%80%bb%e7%bb%93/</guid>
		<description><![CDATA[　　去年写的，后来整理文章时"丢"了，现在把它贴回来。

　　操作系统为每一个进程维护着一个虚拟的地址空间，这个地址空间的大小通常取决于系统的地址线数目，比如在32位系统中，虚拟地址空间的返回就是0×00000000~0xFFFFFFFF，大小共4G。通常操作系统会划分出一部分来专门供内核使用，而不允许用户进程直接访问。Linux内核占用4G中高地址的1G，即0XC0000000~0XFFFFFFFF，windows内核通常占用高地址的2G空间，但也可配置成1G。进程的代码、数据以及共享库等资源终究是要放在物理内存中才能被访问的，操作系统在建立用户进程时，会为其建立各自独立的虚拟地址空间，然后将各自的数据段、代码段、BSS段等映射到这个地址空间，并为其初始化堆、栈等必须的资源。另外，操作系统还将虚拟空间和物理空间都划分成大小相等的页，把进程数据所在虚拟地址空间的各个虚拟页面映射到其真正被加载的物理页面，这种映射是全相联方式的，即任何一个虚页可以被映射到任何一个实页。]]></description>
			<content:encoded><![CDATA[<p>　　去年写的，后来整理文章时&#8221;丢&#8221;了，现在把它贴回来。</p>
<hr />
　　操作系统为每一个进程维护着一个虚拟的地址空间，这个地址空间的大小通常取决于系统的地址线数目，比如在32位系统中，虚拟地址空间的返回就是0×00000000~0xFFFFFFFF，大小共4G。通常操作系统会划分出一部分来专门供内核使用，而不允许用户进程直接访问。Linux内核占用4G中高地址的1G，即0XC0000000~0XFFFFFFFF，windows内核通常占用高地址的2G空间，但也可配置成1G。进程的代码、数据以及共享库等资源终究是要放在物理内存中才能被访问的，操作系统在建立用户进程时，会为其建立各自独立的虚拟地址空间，然后将各自的数据段、代码段、BSS段等映射到这个地址空间，并为其初始化堆、栈等必须的资源。另外，操作系统还将虚拟空间和物理空间都划分成大小相等的页，把进程数据所在虚拟地址空间的各个虚拟页面映射到其真正被加载的物理页面，这种映射是全相联方式的，即任何一个虚页可以被映射到任何一个实页。</p>
<p>　　操作系统采用虚拟内存的方式管理存储器有很多好处：<br />
　　第一，<strong>虚拟内存管理可以控制物理内存的访问权限</strong>。物理内存本身是不限制访问的，任何地址都可以读写，而操作系统要求不同的页面具有不同的访问权限，这是利用CPU模式和MMU的内存保护机制实现的。例如，代码段被只读保护起来，防止被错误的指令意外改写，内核地址空间也被保护起来，防止在用户模式下执行错误的指令意外改写内核数据。这样，执行错误指令或恶意代码的破坏能力受到了限制，顶多使当前进程因段错误终止，而不会影响整个系统的稳定性。</p>
<p>　　第二，<strong>虚拟内存管理最主要的作用是让每个进程有独立的地址空间</strong>。所谓独立的地址空间是指，不同进程中的同一个VA被MMU映射到不同的PA，并且在某一个进程中访问任何地址都不可能访问到另外一个进程的数据，这样使得任何一个进程由于执行错误指令或恶意代码导致的非法内存访问都不会意外改写其它进程的数据，不会影响其它进程的运行，从而保证整个系统的稳定性。另一方面，每个进程都认为自己独占整个虚拟地址空间，这样链接器和加载器的实现会比较容易，不必考虑各进程的地址范围是否冲突。</p>
<p>　　第三，<strong>方便了共享库的实现</strong>。采用共享库的目的在于节省内存(物理内存)，一些公用模块在内存中可以只保存一份，让各进程共享，而不是各自加载一份，当然，只读的代码段可以共享，可写的数据段就必须各自保留一份了。采用虚拟内存机制后，可以将物理内存中所加载的共享库分别映射到进程各自的地址空间，由于加载地址可能不同，所以共享库必须实现为地址无关码(PIC)。</p>
<p>　　第三，<strong>VA到PA的映射会给分配和释放内存带来方便，物理地址不连续的几块内存可以映射成虚拟地址连续的一块内存</strong>。比如要用malloc分配一块很大的内存空间，虽然有足够多的空闲物理内存，却没有足够大的连续空闲内存，这时就可以分配多个不连续的物理页面而映射到连续的虚拟地址范围。</p>
<p>　　第四，<strong>“增加”了程序可以使用的内存空间</strong>。一个系统如果同时运行着很多进程，为各进程分配的内存之和可能会大于实际可用的物理内存，虚拟内存管理使得这种情况下各进程仍然能够正常运行。因为各进程分配的只不过是虚拟内存的页面，这些页面的数据可以映射到物理页面，也可以临时保存到磁盘上而不占用物理页面。当所访问的页面不在内存中时再将其加载进来，无空闲页面的时候还可能需要采取一定的置换算法将某个页面换出。这种机制的可行性得益于伟大的“局部性原理”。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.dutor.net/index.php/2010/04/virtual-memory/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>内存泄漏小陷阱</title>
		<link>http://www.dutor.net/index.php/2009/11/mem-leak-trap/</link>
		<comments>http://www.dutor.net/index.php/2009/11/mem-leak-trap/#comments</comments>
		<pubDate>Wed, 18 Nov 2009 04:36:20 +0000</pubDate>
		<dc:creator>dutor</dc:creator>
				<category><![CDATA[之语言特性]]></category>
		<category><![CDATA[边走编程]]></category>
		<category><![CDATA[字符串]]></category>
		<category><![CDATA[汇编]]></category>
		<category><![CDATA[虚拟内存]]></category>

		<guid isPermaLink="false">http://www.dutor.net/?p=1681</guid>
		<description><![CDATA[<pre lang="cpp" line="1">
int
main()
{
	char * str = new char[32];
	str = "Hello, Piggy!";
	return 0;
}
</pre>
这样是会内存泄漏的……而我一直都不知道……不过想来也自然，因为这样是允许的，char *str = "Hello, Piggy!";，“程序中的字符串被存放在常量存储区”不要把这句话当成耳旁风，谨记。]]></description>
			<content:encoded><![CDATA[
<div class="wp_codebox"><table><tr id="p16813"><td class="line_numbers"><pre>1
2
3
4
5
6
7
</pre></td><td class="code" id="p1681code3"><pre class="cpp" style="font-family:monospace;"><span style="color: #0000ff;">int</span>
main<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span>
<span style="color: #008000;">&#123;</span>
	<span style="color: #0000ff;">char</span> <span style="color: #000040;">*</span> str <span style="color: #000080;">=</span> <span style="color: #0000dd;">new</span> <span style="color: #0000ff;">char</span><span style="color: #008000;">&#91;</span><span style="color: #0000dd;">32</span><span style="color: #008000;">&#93;</span><span style="color: #008080;">;</span>
	str <span style="color: #000080;">=</span> <span style="color: #FF0000;">&quot;Hello, Piggy!&quot;</span><span style="color: #008080;">;</span>
	<span style="color: #0000ff;">return</span> <span style="color: #0000dd;">0</span><span style="color: #008080;">;</span>
<span style="color: #008000;">&#125;</span></pre></td></tr></table></div>

<p>这样是会内存泄漏的……而我一直都不知道……</p>

<div class="wp_codebox"><table><tr id="p16814"><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
</pre></td><td class="code" id="p1681code4"><pre class="asm" style="font-family:monospace;"><span style="color: #339933;">.</span>LC0<span style="color: #339933;">:</span>
	<span style="color: #339933;">.</span>string	<span style="color: #7f007f;">&quot;Hello, Piggy!&quot;</span>
	<span style="color: #339933;">.</span>text
<span style="color: #339933;">.</span>globl main
	<span style="color: #339933;">.</span><span style="color: #000000; font-weight: bold;">type</span>	main<span style="color: #339933;">,</span> @function
main<span style="color: #339933;">:</span>
	andl	$<span style="color: #339933;">-</span><span style="color: #0000ff;">16</span><span style="color: #339933;">,</span> <span style="color: #339933;">%</span><span style="color: #00007f;">esp</span>
	subl	$<span style="color: #0000ff;">32</span><span style="color: #339933;">,</span> <span style="color: #339933;">%</span><span style="color: #00007f;">esp</span>
	movl	$<span style="color: #0000ff;">32</span><span style="color: #339933;">,</span> <span style="color: #009900; font-weight: bold;">&#40;</span><span style="color: #339933;">%</span><span style="color: #00007f;">esp</span><span style="color: #009900; font-weight: bold;">&#41;</span>
	<span style="color: #00007f; font-weight: bold;">call</span>	_Znaj
	movl	<span style="color: #339933;">%</span><span style="color: #00007f;">eax</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">28</span><span style="color: #009900; font-weight: bold;">&#40;</span><span style="color: #339933;">%</span><span style="color: #00007f;">esp</span><span style="color: #009900; font-weight: bold;">&#41;</span>
	movl	$<span style="color: #339933;">.</span>LC0<span style="color: #339933;">,</span> <span style="color: #0000ff;">28</span><span style="color: #009900; font-weight: bold;">&#40;</span><span style="color: #339933;">%</span><span style="color: #00007f;">esp</span><span style="color: #009900; font-weight: bold;">&#41;</span> <span style="color: #666666; font-style: italic;">;把str给覆盖了</span></pre></td></tr></table></div>

<p>不过想来也自然，因为这样是允许的，char *str = &#8220;Hello, Piggy!&#8221;;，“程序中的字符串被存放在常量存储区”不要把这句话当成耳旁风，谨记。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.dutor.net/index.php/2009/11/mem-leak-trap/feed/</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
		<item>
		<title>虚存管理页面调度算法</title>
		<link>http://www.dutor.net/index.php/2009/11/vm-page-schedule/</link>
		<comments>http://www.dutor.net/index.php/2009/11/vm-page-schedule/#comments</comments>
		<pubDate>Wed, 04 Nov 2009 02:23:28 +0000</pubDate>
		<dc:creator>dutor</dc:creator>
				<category><![CDATA[Unix/Linux]]></category>
		<category><![CDATA[OS基础]]></category>
		<category><![CDATA[算法]]></category>
		<category><![CDATA[虚拟内存]]></category>

		<guid isPermaLink="false">http://www.dutor.net/?p=1586</guid>
		<description><![CDATA[<ul>
	<li><strong>最优置换算法(OPT)</strong>
　　最优置换(OPTimal replacement)，顾其名，知其义，这是一种最优的算法，因为对于任一页面请求序列，其产生的缺页中断次数时最少的，但，这只是理论上的最优。其实质是：当调入新的一页而必须预先置换某个老页时，所选择的老页应是将来不再被使用，或者是在最远的将来才被访问。其最优性是容易证明的。
　　但是最优页面置换算法的实现是困难的，因为它需要我们预先就知道一个进程整个运行过程中页面走向的全部情况，而这几乎时不可能的。所以，这个算法主要还是用来衡量其他算法的优劣的。
</li>
</ul>]]></description>
			<content:encoded><![CDATA[<p>　　在虚拟内存管理的实现中，最关键的就是页面的调入策略和页面的置换算法。<br />
　　页面的调入策略主要有两种：预先调入策略和页面请求调入策略。由于前者需要对进程的运行过程进行一定量的预测，所以实现起来比较困难和低效，所以经常采用的是后一种策略，即当执行进程所需的某个页面不在内存时，产生缺页中断，再由专门的缺页中断服务程序(ISR)根据进程页表将所需页面调入内存。</p>
<p>　　当缺页中断服务程序发现，内存中已经没有空闲的物理页面(通常称之为帧)时，就会执行一种页面换出程序，它采取一定的置换算法将某个页面换出到外存的交换(文件)分区。通常，衡量一种页面置换算法性能好坏的指标就是对于大量的页面请求序列，在一定数量的物理帧上，产生缺页中断的平均次数。页面置换算法较多，其变种更多，常常见诸于各大OS教材的主要由下面的几种。</p>
<ul>
<li><strong>先入先出法(FIFO)</strong><br />
　　Fist In Fist Out, 这是一种实现起来最为简单的算法，其实质是，最简单的页面置换算法是先入先出(FIFO)法。这种算法的实质是，总是选择在主存中停留时间<strong>最长(即最老)</strong>的一页置换，即先进入内存的页，先退出内存。理由是：<strong>最早调入内存的页，其不再被使用的可能性比刚调入内存的可能性大。</strong>建立一个FIFO队列，收容所有在内存中的页。被置换页面总是在队列头上进行。当一个页面被放入内存时，就把它插在队尾上。<br />
　　这种算法只是在按线性顺序访问地址空间时才是理想的，否则效率不高。因为那些常被访问的页，往往在主存中也停留得最久，结果它们因变“老”而不得不被置换出去。另外，FIFO算法还有一个比较有意思的缺陷，称之为Berlady异常(或者?)，说当物理内存也即帧数增加时，其缺页中断的次数反而<strong>有可能</strong>增加！
</li>
<li><strong>最优置换算法(OPT)</strong><br />
　　最优置换(OPTimal replacement)，顾其名，知其义，这是一种最优的算法，因为对于任一页面请求序列，其产生的缺页中断次数时最少的，但，这只是理论上的最优。其实质是：当调入新的一页而必须预先置换某个老页时，所选择的老页应是将来不再被使用，或者是在最远的将来才被访问。其最优性是容易证明的。<br />
　　但是最优页面置换算法的实现是困难的，因为它需要我们预先就知道一个进程整个运行过程中页面走向的全部情况，而这几乎时不可能的。所以，这个算法主要还是用来衡量其他算法的优劣的。
</li>
<li><strong>最近最久未使用算法(LRU)</strong><br />
　　最近最久未使用算法(Least-Recently Used)，它的核心思想是，当需要置换一页时，选择在最近一段时间里最久没有使用过的页面予以置换。既然要以时间为替换依据，那么肯定就要用到定时/计数器，因此这个算法通常需要一定的硬件支持，这样的话其通用性也会降低。</p>
<p>　　还有一种LRU的近似算法，最近未使用算法(Not Recently Used，NUR)，相比LRU实现起来更简单一些。它在页表的每一表项中增加一个引用位，操作系统<strong>定期</strong>地将它们置为0。当某一页被访问时，由硬件将该位置1。需要页面替换时，就可把该位是0的页淘汰出去。
</li>
<p>　　
<li><strong>二次机会算法(SC)</strong><br />
　　这是一种FIFO和LRU的折中，或者说结合，它避免了FIFO的缺陷，即可能把经常使用的页面替换出去(比如说装入程序?)。它的思想是：需要页面替换时，检查它的访问位。如果是0，就淘汰这页；如果访问位是1，就将其清0，同时给它第二次机会，然后检验下一个FIFO页面。因此，如果一个页面经常使用，它的访问位总保持为1，它被淘汰出去的几率是很小的。</li>
</ul>
<p>　　<br />
　　还有其他很多页面置换算法，实际使用的算法通常就是这些算法的一些折中或者说变种，可见，要想把一个理论上的好算法应用到具体的问题上，会受到很多限制，还需要做不少其他的工作。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.dutor.net/index.php/2009/11/vm-page-schedule/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>还是虚存</title>
		<link>http://www.dutor.net/index.php/2009/11/vm-again/</link>
		<comments>http://www.dutor.net/index.php/2009/11/vm-again/#comments</comments>
		<pubDate>Sun, 01 Nov 2009 08:14:09 +0000</pubDate>
		<dc:creator>dutor</dc:creator>
				<category><![CDATA[Unix/Linux]]></category>
		<category><![CDATA[之语言特性]]></category>
		<category><![CDATA[OS基础]]></category>
		<category><![CDATA[虚拟内存]]></category>

		<guid isPermaLink="false">http://www.dutor.net/?p=1541</guid>
		<description><![CDATA[　　只占了十分之一左右！这又是为什么呢？永远也学不完的虚拟内存啊！

　　呃……又SB了！const int size = 2^30;这哪里是1G啊！分明是28嘛！Orz...汇编码里面尽是28！这下好了，改成1<<30，运行了四个实例，机器就笨的像猪了：

　　等程序结束了，刚开始运行着到浏览器也慢了一会儿，估计是被换到交换文件里面去了。]]></description>
			<content:encoded><![CDATA[<p>　　看这个简单的程序：</p>

<div class="wp_codebox"><table><tr id="p15415"><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
</pre></td><td class="code" id="p1541code5"><pre class="cpp" style="font-family:monospace;"><span style="color: #339900;">#include &lt;iostream&gt;</span>
<span style="color: #0000ff;">using</span> <span style="color: #0000ff;">namespace</span> std<span style="color: #008080;">;</span>
<span style="color: #0000ff;">int</span>
main<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span>
<span style="color: #008000;">&#123;</span>
    <span style="color: #0000ff;">const</span> <span style="color: #0000ff;">int</span> size <span style="color: #000080;">=</span> <span style="color: #0000dd;">2</span><span style="color: #000040;">^</span><span style="color: #0000dd;">30</span><span style="color: #008080;">;</span>
    <span style="color: #0000ff;">char</span> <span style="color: #000040;">*</span> p <span style="color: #000080;">=</span> <span style="color: #0000dd;">new</span> <span style="color: #0000ff;">char</span><span style="color: #008000;">&#91;</span>size<span style="color: #008000;">&#93;</span><span style="color: #008080;">;</span>
    <span style="color: #0000ff;">for</span><span style="color: #008000;">&#40;</span><span style="color: #0000ff;">int</span> i <span style="color: #000080;">=</span> <span style="color: #0000dd;">0</span><span style="color: #008080;">;</span> i <span style="color: #000080;">&lt;</span> size<span style="color: #008080;">;</span> <span style="color: #000040;">++</span>i<span style="color: #008000;">&#41;</span>
    <span style="color: #008000;">&#123;</span>
        p<span style="color: #008000;">&#91;</span>i<span style="color: #008000;">&#93;</span> <span style="color: #000080;">=</span> <span style="color: #0000dd;">0</span><span style="color: #008080;">;</span>
    <span style="color: #008000;">&#125;</span>
    sleep<span style="color: #008000;">&#40;</span><span style="color: #0000dd;">121</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #0000ff;">return</span> <span style="color: #0000dd;">0</span><span style="color: #008080;">;</span>
<span style="color: #008000;">&#125;</span></pre></td></tr></table></div>

<p>　　在后台运行该程序的多个实例，并查看内存占用：</p>

<div class="wp_codebox"><table><tr id="p15416"><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
</pre></td><td class="code" id="p1541code6"><pre class="bash" style="font-family:monospace;"><span style="color: #7a0874; font-weight: bold;">&#91;</span>04:07 PM<span style="color: #7a0874; font-weight: bold;">&#93;</span> ivan<span style="color: #000000; font-weight: bold;">@</span>ivan-desktop ~<span style="color: #000000; font-weight: bold;">/</span><span style="color: #c20cb9; font-weight: bold;">cpp</span><span style="color: #000000; font-weight: bold;">&gt;</span> .<span style="color: #000000; font-weight: bold;">/</span><span style="color: #7a0874; font-weight: bold;">test</span><span style="color: #000000; font-weight: bold;">&amp;</span>
<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">1</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> <span style="color: #000000;">8345</span>
<span style="color: #7a0874; font-weight: bold;">&#91;</span>04:07 PM<span style="color: #7a0874; font-weight: bold;">&#93;</span> ivan<span style="color: #000000; font-weight: bold;">@</span>ivan-desktop ~<span style="color: #000000; font-weight: bold;">/</span><span style="color: #c20cb9; font-weight: bold;">cpp</span><span style="color: #000000; font-weight: bold;">&gt;</span> .<span style="color: #000000; font-weight: bold;">/</span><span style="color: #7a0874; font-weight: bold;">test</span><span style="color: #000000; font-weight: bold;">&amp;</span>
<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">2</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> <span style="color: #000000;">8346</span>
<span style="color: #7a0874; font-weight: bold;">&#91;</span>04:07 PM<span style="color: #7a0874; font-weight: bold;">&#93;</span> ivan<span style="color: #000000; font-weight: bold;">@</span>ivan-desktop ~<span style="color: #000000; font-weight: bold;">/</span><span style="color: #c20cb9; font-weight: bold;">cpp</span><span style="color: #000000; font-weight: bold;">&gt;</span> .<span style="color: #000000; font-weight: bold;">/</span><span style="color: #7a0874; font-weight: bold;">test</span><span style="color: #000000; font-weight: bold;">&amp;</span>
<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">3</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> <span style="color: #000000;">8347</span>
<span style="color: #7a0874; font-weight: bold;">&#91;</span>04:07 PM<span style="color: #7a0874; font-weight: bold;">&#93;</span> ivan<span style="color: #000000; font-weight: bold;">@</span>ivan-desktop ~<span style="color: #000000; font-weight: bold;">/</span><span style="color: #c20cb9; font-weight: bold;">cpp</span><span style="color: #000000; font-weight: bold;">&gt;</span> .<span style="color: #000000; font-weight: bold;">/</span><span style="color: #7a0874; font-weight: bold;">test</span><span style="color: #000000; font-weight: bold;">&amp;</span>
<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">4</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> <span style="color: #000000;">8348</span>
<span style="color: #7a0874; font-weight: bold;">&#91;</span>04:07 PM<span style="color: #7a0874; font-weight: bold;">&#93;</span> ivan<span style="color: #000000; font-weight: bold;">@</span>ivan-desktop ~<span style="color: #000000; font-weight: bold;">/</span><span style="color: #c20cb9; font-weight: bold;">cpp</span><span style="color: #000000; font-weight: bold;">&gt;</span> <span style="color: #c20cb9; font-weight: bold;">free</span></pre></td></tr></table></div>

<pre>
             total       used       free     shared    buffers     cached
Mem:       1997172    1942672      54500          0     486080    1067476
</pre>
<p>　　只占了十分之一左右！这又是为什么呢？永远也学不完的虚拟内存啊！</p>
<p>　　呃……又SB了！const int size = 2^30;这哪里是1G啊！分明是28嘛！Orz&#8230;汇编码里面尽是28！这下好了，改成1<<30，运行了四个实例，机器就笨的像猪了：<br />
<div class="wp-caption aligncenter" style="width: 626px"><img alt="System Monitor" src="http://www.dutor.net/files/images/vaalloc.png" title="System Monitor" width="616" height="523" /><p class="wp-caption-text">System Monitor</p></div></p>
<p>　　等程序结束了，刚开始运行着到浏览器也慢了一会儿，估计是被换到交换文件里面去了。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.dutor.net/index.php/2009/11/vm-again/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>虚拟内存管理总结</title>
		<link>http://www.dutor.net/index.php/2009/09/summary-vm/</link>
		<comments>http://www.dutor.net/index.php/2009/09/summary-vm/#comments</comments>
		<pubDate>Fri, 04 Sep 2009 23:51:57 +0000</pubDate>
		<dc:creator>dutor</dc:creator>
				<category><![CDATA[尚未分类]]></category>
		<category><![CDATA[OS基础]]></category>
		<category><![CDATA[虚拟内存]]></category>

		<guid isPermaLink="false">http://www.dutor.net/?p=1252</guid>
		<description><![CDATA[　　操作系统为每一个进程维护着一个虚拟的地址空间，这个地址空间的大小通常取决于系统的地址线数目，比如在32位系统中，虚拟地址空间的返回就是0x00000000~0xFFFFFFFF，大小共4G。通常操作系统会划分出一部分来专门供内核使用，而不允许用户进程直接访问。Linux内核占用4G中高地址的1G，即0XC0000000~0XFFFFFFFF，windows内核通常占用高地址的2G空间，但也可配置成1G。进程的代码、数据以及共享库等资源终究是要放在物理内存中才能被访问的，操作系统在建立用户进程时，会为其建立各自独立的虚拟地址空间，然后将各自的数据段、代码段、BSS段等映射到这个地址空间，并为其初始化堆、栈等必须的资源。另外，操作系统还将虚拟空间和物理空间都划分成大小相等的页，把进程数据所在虚拟地址空间的各个虚拟页面映射到其真正被加载的物理页面，这种映射是全相联方式的，即任何一个虚页可以被映射到任何一个实页。]]></description>
			<content:encoded><![CDATA[<p>　　操作系统为每一个进程维护着一个虚拟的地址空间，这个地址空间的大小通常取决于系统的地址线数目，比如在32位系统中，虚拟地址空间的返回就是0&#215;00000000~0xFFFFFFFF，大小共4G。通常操作系统会划分出一部分来专门供内核使用，而不允许用户进程直接访问。Linux内核占用4G中高地址的1G，即0XC0000000~0XFFFFFFFF，windows内核通常占用高地址的2G空间，但也可配置成1G。进程的代码、数据以及共享库等资源终究是要放在物理内存中才能被访问的，操作系统在建立用户进程时，会为其建立各自独立的虚拟地址空间，然后将各自的数据段、代码段、BSS段等映射到这个地址空间，并为其初始化堆、栈等必须的资源。另外，操作系统还将虚拟空间和物理空间都划分成大小相等的页，把进程数据所在虚拟地址空间的各个虚拟页面映射到其真正被加载的物理页面，这种映射是全相联方式的，即任何一个虚页可以被映射到任何一个实页。</p>
<p>　　操作系统采用虚拟内存的方式管理存储器有很多好处：</p>
<p>　　<strong>第一，虚拟内存管理可以控制物理内存的访问权限。</strong>物理内存本身是不限制访问的，任何地址都可以读写，而操作系统要求不同的页面具有不同的访问权限，这是利用CPU模式和MMU的内存保护机制实现的。例如，代码段被只读保护起来，防止被错误的指令意外改写，内核地址空间也被保护起来，防止在用户模式下执行错误的指令意外改写内核数据。这样，执行错误指令或恶意代码的破坏能力受到了限制，顶多使当前进程因段错误终止，而不会影响整个系统的稳定性。</p>
<p>　　<strong>第二，虚拟内存管理最主要的作用是让每个进程有独立的地址空间。</strong>所谓<strong>独立</strong>的地址空间是指，不同进程中的同一个VA被MMU映射到不同的PA，并且在某一个进程中访问任何地址都不可能访问到另外一个进程的数据，这样使得任何一个进程由于执行错误指令或恶意代码导致的非法内存访问都不会意外改写其它进程的数据，不会影响其它进程的运行，从而保证整个系统的稳定性。另一方面，每个进程都认为自己独占整个虚拟地址空间，这样链接器和加载器的实现会比较容易，不必考虑各进程的地址范围是否冲突。</p>
<p>　　<strong>第三，方便了共享库的实现。</strong>采用共享库的目的在于节省内存(物理内存)，一些公用模块在内存中可以只保存一份，让各进程共享，而不是各自加载一份，当然，只读的代码段可以共享，可写的数据段就必须各自保留一份了。采用虚拟内存机制后，可以将物理内存中所加载的共享库分别映射到进程各自的地址空间，由于加载地址可能不同，所以共享库必须实现为地址无关码(PIC)。</p>
<p>　　<strong>第三，VA到PA的映射会给分配和释放内存带来方便，物理地址不连续的几块内存可以映射成虚拟地址连续的一块内存。</strong>比如要用malloc分配一块很大的内存空间，虽然有足够多的空闲物理内存，却没有足够大的连续空闲内存，这时就可以分配多个不连续的物理页面而映射到连续的虚拟地址范围。</p>
<p>　　<strong>第四，“增加”了程序可以使用的内存空间。</strong>一个系统如果同时运行着很多进程，为各进程分配的内存之和可能会大于实际可用的物理内存，虚拟内存管理使得这种情况下各进程仍然能够正常运行。因为各进程分配的只不过是虚拟内存的页面，这些页面的数据可以映射到物理页面，也可以临时保存到磁盘上而不占用物理页面。当所访问的页面不在内存中时再将其加载进来，无空闲页面的时候还可能需要采取一定的置换算法将某个页面换出。这种机制的可行性得益于伟大的“局部性原理”。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.dutor.net/index.php/2009/09/summary-vm/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>匿名管道</title>
		<link>http://www.dutor.net/index.php/2009/08/anonymous-pipe/</link>
		<comments>http://www.dutor.net/index.php/2009/08/anonymous-pipe/#comments</comments>
		<pubDate>Fri, 28 Aug 2009 03:09:37 +0000</pubDate>
		<dc:creator>dutor</dc:creator>
				<category><![CDATA[Unix/Linux]]></category>
		<category><![CDATA[边走编程]]></category>
		<category><![CDATA[OS基础]]></category>
		<category><![CDATA[多线程]]></category>
		<category><![CDATA[管道]]></category>
		<category><![CDATA[虚拟内存]]></category>

		<guid isPermaLink="false">http://www.dutor.net/?p=1213</guid>
		<description><![CDATA[　　管道是Linux支持的 IPC形式之一，具有以下特点：
<ul>

	<li>管道是半双工的，数据只能向一个方向流动；需要双方通信时，需要建立起两个管道；</li>

	<li>只能用于父子进程或者兄弟进程之间（具有亲缘关系的进程）；</li>

	<li>单独构成一种独立的文件系统：管道对于管道两端的进程而言，就是一个文件，但它不是普通的文件，它不属于某种文件系统，而是自立门户，单独构成一种文件系统，并且只存在与内存中。</li>

	<li>数据的读出和写入：一个进程向管道中写的内容被管道另一端的进程读出。写入的内容每次都添加在管道缓冲区的末尾，并且每次都是从缓冲区的头部读出数据。</li>

</ul>]]></description>
			<content:encoded><![CDATA[<h6>管道概念</h6>
<p>　　管道是Linux支持的 IPC形式之一，具有以下特点：</p>
<ul>
<li>管道是半双工的，数据只能向一个方向流动；需要双方通信时，需要建立起两个管道；</li>
<li>只能用于父子进程或者兄弟进程之间（具有亲缘关系的进程）；</li>
<li>单独构成一种独立的文件系统：管道对于管道两端的进程而言，就是一个文件，但它不是普通的文件，它不属于某种文件系统，而是自立门户，单独构成一种文件系统，并且只存在与内存中。</li>
<li>数据的读出和写入：一个进程向管道中写的内容被管道另一端的进程读出。写入的内容每次都添加在管道缓冲区的末尾，并且每次都是从缓冲区的头部读出数据。</li>
</ul>
<p>　　匿名管道是通过pipe()函数创建的：</p>

<div class="wp_codebox"><table><tr id="p12137"><td class="line_numbers"><pre>1
2
3
</pre></td><td class="code" id="p1213code7"><pre class="cpp" style="font-family:monospace;"><span style="color: #339900;">#include &lt;unistd.h&gt;</span>
<span style="color: #0000ff;">int</span> fd<span style="color: #008000;">&#91;</span><span style="color: #0000dd;">2</span><span style="color: #008000;">&#93;</span><span style="color: #008080;">;</span>
<span style="color: #0000ff;">int</span> pipe<span style="color: #008000;">&#40;</span> fd<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span></pre></td></tr></table></div>

<p>　　该函数创建的管道的两端处于一个进程中间，在实际应用中没有太大意义，因此，一个进程在由pipe()创建管道后，一般再fork一个子进程，然后通过管道实现父子进程间的通信（因此也不难推出，只要两个进程中存在亲缘关系，这里的亲缘关系指的是具有共同的祖先，都可以采用管道方式来进行通信）。</p>
<h6>管道的读写规则</h6>
<p>　　管道两端可分别用描述字fd[0]以及fd[1]来描述，需要注意的是，管道的两端是固定了任务的。即一端只能用于读，由描述字fd[0]表示，称其为管道读端；另一端则只能用于写，由描述字fd[1]来表示，称其为管道写端。如果试图从管道写端读取数据，或者向管道读端写入数据都将导致错误发生。一般文件的I/O函数都可以用于管道，如close、read、write等等。</p>
<p><strong>从管道中读取数据：</strong></p>
<ul>
<li>如果管道的写端不存在，则认为已经读到了数据的末尾，读函数返回的读出字节数为0；</li>
<li>当管道的写端存在时，如果请求的字节数目大于PIPE_BUF，则返回管道中现有的数据字节数，如果请求的字节数目不大于PIPE_BUF，则返回管道中现有数据字节数（此时，管道中数据量小于请求的数据量）；或者返回请求的字节数（此时，管道中数据量不小于请求的数据量）。</li>
</ul>
<p><strong>向管道中写入数据：</strong></p>
<ul>
<li>向管道中写入数据时，linux将不保证写入的原子性，管道缓冲区一有空闲区域，写进程就会试图向管道写入数据。如果读进程不读走管道缓冲区中的数据，那么写操作将一直阻塞。 </li>
<li>只有在管道的读端存在时，向管道中写入数据才有意义。否则，向管道中写入数据的进程将收到内核传来的SIFPIPE信号，应用程序可以处理该信号，也可以忽略（默认动作则是应用程序终止）。</li>
</ul>
<h6>示例代码：</h6>

<div class="wp_codebox"><table><tr id="p12138"><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
</pre></td><td class="code" id="p1213code8"><pre class="cpp" style="font-family:monospace;"><span style="color: #339900;">#include &lt;stdio.h&gt;</span>
<span style="color: #339900;">#include &lt;string.h&gt;</span>
<span style="color: #339900;">#include &lt;unistd.h&gt;</span>
<span style="color: #339900;">#include &lt;sys/types.h&gt;</span>
&nbsp;
<span style="color: #0000ff;">int</span>
main<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span>
<span style="color: #008000;">&#123;</span>
    <span style="color: #0000ff;">int</span> fd<span style="color: #008000;">&#91;</span><span style="color: #0000dd;">2</span><span style="color: #008000;">&#93;</span><span style="color: #008080;">;</span>
    <span style="color: #0000ff;">char</span> rbuf<span style="color: #008000;">&#91;</span><span style="color: #0000dd;">10</span><span style="color: #008000;">&#93;</span><span style="color: #008080;">;</span> <span style="color: #666666;">//~ 读缓冲</span>
    <span style="color: #0000ff;">char</span> wbuf<span style="color: #008000;">&#91;</span><span style="color: #0000dd;">5120</span><span style="color: #008000;">&#93;</span><span style="color: #008080;">;</span><span style="color: #666666;">//~ 写缓冲</span>
    <span style="color: #0000ff;">size_t</span> rsize<span style="color: #008080;">;</span>
    pid_t pid<span style="color: #008080;">;</span>
    <span style="color: #0000ff;">if</span><span style="color: #008000;">&#40;</span>pipe<span style="color: #008000;">&#40;</span>fd<span style="color: #008000;">&#41;</span> <span style="color: #000080;">==</span> <span style="color: #000040;">-</span><span style="color: #0000dd;">1</span><span style="color: #008000;">&#41;</span>
        <span style="color: #0000dd;">printf</span><span style="color: #008000;">&#40;</span><span style="color: #FF0000;">&quot;pipe create failure<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #0000ff;">if</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#40;</span>pid <span style="color: #000080;">=</span> fork<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span> <span style="color: #000080;">&lt;</span> <span style="color: #0000dd;">0</span><span style="color: #008000;">&#41;</span>
        <span style="color: #0000dd;">printf</span><span style="color: #008000;">&#40;</span><span style="color: #FF0000;">&quot;process create failure<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #0000ff;">if</span><span style="color: #008000;">&#40;</span>pid <span style="color: #000080;">==</span> <span style="color: #0000dd;">0</span><span style="color: #008000;">&#41;</span> <span style="color: #666666;">//~ 子进程写</span>
    <span style="color: #008000;">&#123;</span>
        <span style="color: #666666;">//close(fd[0]); //!~ 若此处将读端关闭，则管道就没有打开的读端，也无法写入。</span>
        <span style="color: #0000ff;">while</span><span style="color: #008000;">&#40;</span>rsize <span style="color: #000080;">=</span> <span style="color: #0000dd;">fread</span><span style="color: #008000;">&#40;</span>wbuf, <span style="color: #0000dd;">1</span>, <span style="color: #0000dd;">sizeof</span><span style="color: #008000;">&#40;</span>wbuf<span style="color: #008000;">&#41;</span>, <span style="color: #0000ff;">stdin</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span>
        <span style="color: #008000;">&#123;</span>
            rsize <span style="color: #000080;">=</span> write<span style="color: #008000;">&#40;</span>fd<span style="color: #008000;">&#91;</span><span style="color: #0000dd;">1</span><span style="color: #008000;">&#93;</span>, wbuf, rsize<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
            <span style="color: #0000dd;">printf</span><span style="color: #008000;">&#40;</span><span style="color: #FF0000;">&quot;write: %d<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span>, rsize<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
        <span style="color: #008000;">&#125;</span>
        close<span style="color: #008000;">&#40;</span>fd<span style="color: #008000;">&#91;</span><span style="color: #0000dd;">1</span><span style="color: #008000;">&#93;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #008000;">&#125;</span>
    <span style="color: #0000ff;">else</span> <span style="color: #0000ff;">if</span><span style="color: #008000;">&#40;</span>pid <span style="color: #000080;">&gt;</span> <span style="color: #0000dd;">0</span><span style="color: #008000;">&#41;</span> <span style="color: #666666;">//~ 父进程读</span>
    <span style="color: #008000;">&#123;</span>
        <span style="color: #666666;">//~ sleep(1);</span>
        close<span style="color: #008000;">&#40;</span>fd<span style="color: #008000;">&#91;</span><span style="color: #0000dd;">1</span><span style="color: #008000;">&#93;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
        close<span style="color: #008000;">&#40;</span>fd<span style="color: #008000;">&#91;</span><span style="color: #0000dd;">0</span><span style="color: #008000;">&#93;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><span style="color: #666666;">//~读端写端均关闭，此时父进程不做任何事。</span>
        sleep<span style="color: #008000;">&#40;</span><span style="color: #0000dd;">9</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
        <span style="color: #0000ff;">while</span><span style="color: #008000;">&#40;</span><span style="color: #0000dd;">1</span><span style="color: #008000;">&#41;</span>
        <span style="color: #008000;">&#123;</span>
            sleep<span style="color: #008000;">&#40;</span><span style="color: #0000dd;">1</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
            <span style="color: #666666;">//~ rsize = read(fd[0], rbuf, sizeof(rbuf));</span>
            <span style="color: #666666;">//~ fprintf(stderr, &quot;%d &quot;, rsize);</span>
            <span style="color: #666666;">//~ fwrite(rbuf,1 , rsize, stderr);</span>
            <span style="color: #666666;">//~ fprintf(stderr, &quot;\n&quot;);</span>
        <span style="color: #008000;">&#125;</span>
    <span style="color: #008000;">&#125;</span>
    <span style="color: #0000ff;">return</span> <span style="color: #0000dd;">0</span><span style="color: #008080;">;</span>
<span style="color: #008000;">&#125;</span></pre></td></tr></table></div>

<h6>疑问</h6>
<p>　　上述程序运行时，当输入字符串大于写缓冲时，为何没有阻塞？对于一下输入：</p>
<blockquote><p>There&#8217;s a whole lot of laughing gas in the atmosphere these days. But it&#8217;s no laughing matter. Nitrous oxide, or N2O, wafts up from manure and the chemical fertilizer sprayed on fields. Industry contributes as well<br />
&#8230;&#8230;.<br />
There&#8217;s a whole lot of laughing gas in the atmosphere these days. But it&#8217;s no laughing matter. Nitrous oxide, or N2O, wafts up from manure and the chemical fertilizer sprayed on fields. Industry contributes as well
</p></blockquote>
<p>产生的输出：</p>
<pre>
write: 4096
write: 4096
write: 4096
write: 4096
write: 4096
write: 4096
</pre>
<p>　　这是为什么呢？:-(</p>
]]></content:encoded>
			<wfw:commentRss>http://www.dutor.net/index.php/2009/08/anonymous-pipe/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>还是delete</title>
		<link>http://www.dutor.net/index.php/2009/08/delete-ag/</link>
		<comments>http://www.dutor.net/index.php/2009/08/delete-ag/#comments</comments>
		<pubDate>Sat, 22 Aug 2009 02:35:10 +0000</pubDate>
		<dc:creator>dutor</dc:creator>
				<category><![CDATA[之语言特性]]></category>
		<category><![CDATA[边走编程]]></category>
		<category><![CDATA[C]]></category>
		<category><![CDATA[delete]]></category>
		<category><![CDATA[虚拟内存]]></category>

		<guid isPermaLink="false">http://www.dutor.net/?p=1141</guid>
		<description><![CDATA[表明看来似乎合情合理，由于C++的多态特性，允许我们将一个子类地址赋给父类型的指针pb，释放对象时理所当然的对pb进行delete。但，在程序运行时，并没有输出M destructed...，即D::m的析构函数没有被调用，而m的析构函数是需要D::~D()来调用的，所以子类D的析构函数也没有被调用。这是很容易理解的，因为父类的析构函数不是virtual的。由此，我们得出结论，用来继承的父类的析构函数总应该是virtual的，除非你确定它绝对不会被用于多态。关于这一点，《Effective C++》里面已经讲到了。

除了上面的问题，我们还应该关心的是，尽管析构函数没有被调用，那M::i的空间被释放了吗？It's a question！由于析构函数没有被调用，那么释放M::i的任务就完全落在了delete身上的了，那么delete做到了吗？It's a very question！这又回到了<a href="http://www.dutor.net/index.php/2009/08/free-delete/" target="_blank">上一篇日志</a>中所描述的问题上了。我的观点是delete做到了它应该做的事情，它只负责释放当初new申请的空间，即对象<strong>本身</strong>，至于对象里面是否有动态申请的内存，那就不是delete而是对象析构函数自己的工作了。]]></description>
			<content:encoded><![CDATA[<p>以前写过一篇<a href="http://www.dutor.net/index.php/2009/08/free-delete/" target="_blank">关于delete</a>的日志，那里提到的只是一个实验而已，我想正常人不会犯那么弱智的错误吧。但接下来的这个问题就不得不加倍留心了。直接看代码：</p>

<div class="wp_codebox"><table><tr id="p11419"><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
</pre></td><td class="code" id="p1141code9"><pre class="cpp" style="font-family:monospace;"><span style="color: #339900;">#include &lt;iostream&gt;</span>
<span style="color: #339900;">#include &lt;pthread.h&gt;</span>
<span style="color: #0000ff;">using</span> <span style="color: #0000ff;">namespace</span> std<span style="color: #008080;">;</span>
&nbsp;
<span style="color: #0000ff;">class</span> M
<span style="color: #008000;">&#123;</span>
    <span style="color: #0000ff;">public</span><span style="color: #008080;">:</span>
        M<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#123;</span><span style="color: #008000;">&#125;</span>
        ~M<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span>
        <span style="color: #008000;">&#123;</span>
            <span style="color: #0000dd;">cout</span><span style="color: #000080;">&lt;&lt;</span><span style="color: #FF0000;">&quot;M destructed...&quot;</span><span style="color: #000080;">&lt;&lt;</span>endl<span style="color: #008080;">;</span>
        <span style="color: #008000;">&#125;</span>
    <span style="color: #0000ff;">private</span><span style="color: #008080;">:</span>
        <span style="color: #0000ff;">int</span> i<span style="color: #008080;">;</span>
<span style="color: #008000;">&#125;</span><span style="color: #008080;">;</span>
<span style="color: #0000ff;">class</span> B
<span style="color: #008000;">&#123;</span>
    <span style="color: #0000ff;">public</span><span style="color: #008080;">:</span>
        B<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#123;</span><span style="color: #008000;">&#125;</span>
        <span style="color: #666666;">//! virtual ~B(){}</span>
        ~B<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#123;</span><span style="color: #008000;">&#125;</span>
<span style="color: #008000;">&#125;</span><span style="color: #008080;">;</span>
<span style="color: #0000ff;">class</span> D<span style="color: #008080;">:</span> <span style="color: #0000ff;">public</span> B
<span style="color: #008000;">&#123;</span>
    <span style="color: #0000ff;">public</span><span style="color: #008080;">:</span>
        D<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#123;</span><span style="color: #008000;">&#125;</span>
        ~D<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#123;</span><span style="color: #008000;">&#125;</span>
    <span style="color: #0000ff;">private</span><span style="color: #008080;">:</span>
        M m<span style="color: #008080;">;</span>
<span style="color: #008000;">&#125;</span><span style="color: #008080;">;</span>
&nbsp;
<span style="color: #0000ff;">int</span>
main<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span>
<span style="color: #008000;">&#123;</span>
    B <span style="color: #000040;">*</span> pb <span style="color: #000080;">=</span> <span style="color: #0000dd;">new</span> D<span style="color: #008080;">;</span>
    <span style="color: #0000dd;">delete</span> pb<span style="color: #008080;">;</span>
    <span style="color: #0000ff;">return</span> <span style="color: #0000dd;">0</span><span style="color: #008080;">;</span>
<span style="color: #008000;">&#125;</span></pre></td></tr></table></div>

<p>表明看来似乎合情合理，由于C++的多态特性，允许我们将一个子类地址赋给父类型的指针pb，释放对象时理所当然的对pb进行delete。但，在程序运行时，并没有输出M destructed&#8230;，即D::m的析构函数没有被调用，而m的析构函数是需要D::~D()来调用的，所以子类D的析构函数也没有被调用。这是很容易理解的，因为父类的析构函数不是virtual的。由此，我们得出结论，用来继承的父类的析构函数总应该是virtual的，除非你确定它绝对不会被用于多态。关于这一点，《Effective C++》里面已经讲到了。</p>
<p>除了上面的问题，我们还应该关心的是，尽管析构函数没有被调用，那M::i的空间被释放了吗？It&#8217;s a question！由于析构函数没有被调用，那么释放M::i的任务就完全落在了delete身上的了，那么delete做到了吗？It&#8217;s a very question！这又回到了<a href="http://www.dutor.net/index.php/2009/08/free-delete/" target="_blank">上一篇日志</a>中所描述的问题上了。我的观点是delete做到了它应该做的事情，它只负责释放当初new申请的空间，即对象<strong>本身</strong>，至于对象里面是否有动态申请的内存，那就不是delete而是对象析构函数自己的工作了。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.dutor.net/index.php/2009/08/delete-ag/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>关于free和delete</title>
		<link>http://www.dutor.net/index.php/2009/08/free-delete/</link>
		<comments>http://www.dutor.net/index.php/2009/08/free-delete/#comments</comments>
		<pubDate>Sat, 15 Aug 2009 12:01:44 +0000</pubDate>
		<dc:creator>dutor</dc:creator>
				<category><![CDATA[之语言特性]]></category>
		<category><![CDATA[边走编程]]></category>
		<category><![CDATA[C]]></category>
		<category><![CDATA[虚拟内存]]></category>

		<guid isPermaLink="false">http://www.dutor.net/?p=1081</guid>
		<description><![CDATA[这里的内存会被正确释放吗？答案要分两方面来讨论。*pd对象本身的内存(4Byte)会不会被释放，就像上例中所说，我还是不知道。但(*pd)::pi所指向的内存肯定是打了水漂啦！因为delete看到的只是一个char*类型的pd，只会简单做一些处理(待高人讲解)，而不会调用析构函数demo::~demo()。甚至有时候它会调用其他类的析构函数：
<pre lang="cpp" line="1">
#include <iostream>
using namespace std;
class demo
{
    public:
        //~ 此处省略代码数行……
        ~demo()
        {
             delete [] pi;
        }
    private:
        int * pi;
};

class foo
{
public:
    ~foo(){cout<<"foo's collapsing..."<<endl;
};
int
main()
{
    demo * pd = new demo;
    delete (foo*)pd;
    return 0;
}
</pre>
foo童鞋真是可怜，让我们来了个借尸还魂，Orz，借刀杀人才对！]]></description>
			<content:encoded><![CDATA[<p>本篇日志，纯属娱乐，没有太大实用价值，在百度上面看到，借题发挥而已……</p>

<div class="wp_codebox"><table><tr id="p108110"><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
</pre></td><td class="code" id="p1081code10"><pre class="cpp" style="font-family:monospace;"><span style="color: #339900;">#include &lt;stdio.h&gt;</span>
<span style="color: #0000ff;">int</span>
main<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span>
<span style="color: #008000;">&#123;</span>
    <span style="color: #0000ff;">int</span><span style="color: #000040;">*</span> pi <span style="color: #000080;">=</span> <span style="color: #008000;">&#40;</span><span style="color: #0000ff;">int</span><span style="color: #000040;">*</span><span style="color: #008000;">&#41;</span><span style="color: #0000dd;">malloc</span><span style="color: #008000;">&#40;</span><span style="color: #0000dd;">sizeof</span><span style="color: #008000;">&#40;</span><span style="color: #0000ff;">int</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #0000dd;">free</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#40;</span><span style="color: #0000ff;">char</span><span style="color: #000040;">*</span><span style="color: #008000;">&#41;</span>pi<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #0000ff;">return</span> <span style="color: #0000dd;">0</span><span style="color: #008080;">;</span>
<span style="color: #008000;">&#125;</span></pre></td></tr></table></div>

<p>这段程序的内存能完全释放吗？答案是能。<br />
看free函数的原型：void free(void*); 可知，无论你传给它什么类型的指针，它内部都是按照没有类型的void*来处理的。堆管理器会帮程序处理这一切，它记录了你先前申请的这块内存的大小，它看到的只是一块内存，没有任何类型之类的东西。</p>
<p>再看下面这段代码：</p>

<div class="wp_codebox"><table><tr id="p108111"><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
</pre></td><td class="code" id="p1081code11"><pre class="cpp" style="font-family:monospace;"><span style="color: #339900;">#include &lt;iostream&gt;</span>
<span style="color: #0000ff;">using</span> <span style="color: #0000ff;">namespace</span> std<span style="color: #008080;">;</span>
<span style="color: #0000ff;">int</span>
main<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span>
<span style="color: #008000;">&#123;</span>
    <span style="color: #0000ff;">int</span><span style="color: #000040;">*</span> pi <span style="color: #000080;">=</span> <span style="color: #0000dd;">new</span> <span style="color: #0000ff;">int</span><span style="color: #008080;">;</span>
    <span style="color: #0000dd;">delete</span> <span style="color: #008000;">&#40;</span><span style="color: #0000ff;">char</span><span style="color: #000040;">*</span><span style="color: #008000;">&#41;</span> pi<span style="color: #008080;">;</span>
    <span style="color: #0000ff;">return</span> <span style="color: #0000dd;">0</span><span style="color: #008080;">;</span>
<span style="color: #008000;">&#125;</span></pre></td></tr></table></div>

<p>这里的内存被正确释放了吗？答案我也不知道……还请看到的高手解答^_^:-)<br />
接着看，</p>

<div class="wp_codebox"><table><tr id="p108112"><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
</pre></td><td class="code" id="p1081code12"><pre class="cpp" style="font-family:monospace;"><span style="color: #339900;">#include &lt;iostream&gt;</span>
<span style="color: #0000ff;">using</span> <span style="color: #0000ff;">namespace</span> std<span style="color: #008080;">;</span>
<span style="color: #0000ff;">class</span> demo
<span style="color: #008000;">&#123;</span>
    <span style="color: #0000ff;">public</span><span style="color: #008080;">:</span>
        <span style="color: #666666;">//~ 此处省略代码数行……</span>
        ~demo<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span>
        <span style="color: #008000;">&#123;</span>
             <span style="color: #0000dd;">delete</span> <span style="color: #008000;">&#91;</span><span style="color: #008000;">&#93;</span> pi<span style="color: #008080;">;</span>
        <span style="color: #008000;">&#125;</span>
    <span style="color: #0000ff;">private</span><span style="color: #008080;">:</span>
        <span style="color: #0000ff;">int</span> <span style="color: #000040;">*</span> pi<span style="color: #008080;">;</span>
<span style="color: #008000;">&#125;</span><span style="color: #008080;">;</span>
<span style="color: #0000ff;">int</span>
main<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span>
<span style="color: #008000;">&#123;</span>
    demo <span style="color: #000040;">*</span> pd <span style="color: #000080;">=</span> <span style="color: #0000dd;">new</span> demo<span style="color: #008080;">;</span>
    <span style="color: #0000dd;">delete</span> <span style="color: #008000;">&#40;</span><span style="color: #0000ff;">char</span><span style="color: #000040;">*</span><span style="color: #008000;">&#41;</span>pd<span style="color: #008080;">;</span>
    <span style="color: #0000ff;">return</span> <span style="color: #0000dd;">0</span><span style="color: #008080;">;</span>
<span style="color: #008000;">&#125;</span></pre></td></tr></table></div>

<p>这里的内存会被正确释放吗？答案要分两方面来讨论。*pd对象本身的内存(4Byte)会不会被释放，就像上例中所说，我还是不知道。但(*pd)::pi所指向的内存肯定是打了水漂啦！因为delete看到的只是一个char*类型的pd，只会简单做一些处理(待高人讲解)，而不会调用析构函数demo::~demo()。甚至有时候它还可能调用其他类的析构函数：</p>

<div class="wp_codebox"><table><tr id="p108113"><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
</pre></td><td class="code" id="p1081code13"><pre class="cpp" style="font-family:monospace;"><span style="color: #339900;">#include &lt;iostream&gt;</span>
<span style="color: #0000ff;">using</span> <span style="color: #0000ff;">namespace</span> std<span style="color: #008080;">;</span>
<span style="color: #0000ff;">class</span> demo
<span style="color: #008000;">&#123;</span>
    <span style="color: #0000ff;">public</span><span style="color: #008080;">:</span>
        <span style="color: #666666;">//~ 此处省略代码数行……</span>
        ~demo<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span>
        <span style="color: #008000;">&#123;</span>
             <span style="color: #0000dd;">delete</span> <span style="color: #008000;">&#91;</span><span style="color: #008000;">&#93;</span> pi<span style="color: #008080;">;</span>
        <span style="color: #008000;">&#125;</span>
    <span style="color: #0000ff;">private</span><span style="color: #008080;">:</span>
        <span style="color: #0000ff;">int</span> <span style="color: #000040;">*</span> pi<span style="color: #008080;">;</span>
<span style="color: #008000;">&#125;</span><span style="color: #008080;">;</span>
&nbsp;
<span style="color: #0000ff;">class</span> foo
<span style="color: #008000;">&#123;</span>
<span style="color: #0000ff;">public</span><span style="color: #008080;">:</span>
    ~foo<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#123;</span><span style="color: #0000dd;">cout</span><span style="color: #000080;">&lt;&lt;</span><span style="color: #FF0000;">&quot;foo's collapsing...&quot;</span><span style="color: #000080;">&lt;&lt;</span>endl<span style="color: #008080;">;</span>
<span style="color: #008000;">&#125;</span><span style="color: #008080;">;</span>
<span style="color: #0000ff;">int</span>
main<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span>
<span style="color: #008000;">&#123;</span>
    demo <span style="color: #000040;">*</span> pd <span style="color: #000080;">=</span> <span style="color: #0000dd;">new</span> demo<span style="color: #008080;">;</span>
    <span style="color: #0000dd;">delete</span> <span style="color: #008000;">&#40;</span>foo<span style="color: #000040;">*</span><span style="color: #008000;">&#41;</span>pd<span style="color: #008080;">;</span>
    <span style="color: #0000ff;">return</span> <span style="color: #0000dd;">0</span><span style="color: #008080;">;</span>
<span style="color: #008000;">&#125;</span></pre></td></tr></table></div>

<p>foo童鞋真是可怜，让我们来了个借尸还魂，Orz，是借刀杀人才对！</p>
]]></content:encoded>
			<wfw:commentRss>http://www.dutor.net/index.php/2009/08/free-delete/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>C++式的告白</title>
		<link>http://www.dutor.net/index.php/2009/08/cpplize-confession/</link>
		<comments>http://www.dutor.net/index.php/2009/08/cpplize-confession/#comments</comments>
		<pubDate>Fri, 14 Aug 2009 08:18:30 +0000</pubDate>
		<dc:creator>dutor</dc:creator>
				<category><![CDATA[之语言特性]]></category>
		<category><![CDATA[尚未分类]]></category>
		<category><![CDATA[C]]></category>
		<category><![CDATA[囧Orz]]></category>
		<category><![CDATA[日记]]></category>
		<category><![CDATA[虚拟内存]]></category>

		<guid isPermaLink="false">http://www.dutor.net/?p=1075</guid>
		<description><![CDATA[<pre>
我能抽象出整个世界．．． 
但是我不能抽象出你．．． 
因为你在我心中是那么的具体．．． 
所以我的世界并不完整．．． 
我可以重载甚至覆盖这个世界里的任何一种方法．．． 
但是我却不能重载对你的思念．．． 
也许命中注定了 你在我的世界里永远的烙上了静态的属性．．． 
而我不慎调用了爱你这个方法．．． 
当我义无返顾的把自己作为参数传进这个方法时．．． 
我才发现爱上你是一个死循环．．． 
它不停的返回对你的思念压入我心里的堆栈．．． 
在这无尽的黑夜中．．． 
我的内存里已经再也装不下别人．．． 
我不停的向系统申请空间．．． 
但却捕获一个异常－－－我爱的人不爱我．．． 
为了解决这个异常．．． 
我愿意虚拟出最后一点内存．．． 
把所有我能实现的方法地址压入堆栈．．． 
并且在栈尾压入最后一个方法－－－将字符串＂我爱你，你爱我吗？＂传递给你．．． 
如果返回值为真－－我将用尽一生去爱你．．． 
否则－－我将释放掉所有系统资源 
</pre>]]></description>
			<content:encoded><![CDATA[<pre>
我能抽象出整个世界．．．
但是我不能抽象出你．．．
因为你在我心中是那么的具体．．．
所以我的世界并不完整．．．
我可以重载甚至覆盖这个世界里的任何一种方法．．．
但是我却不能重载对你的思念．．．
也许命中注定了 你在我的世界里永远的烙上了静态的属性．．．
而我不慎调用了爱你这个方法．．．
当我义无返顾的把自己作为参数传进这个方法时．．．
我才发现爱上你是一个死循环．．．
它不停的返回对你的思念压入我心里的堆栈．．．
在这无尽的黑夜中．．．
我的内存里已经再也装不下别人．．．
我不停的向系统申请空间．．．
但却捕获一个异常－－－我爱的人不爱我．．．
为了解决这个异常．．．
我愿意虚拟出最后一点内存．．．
把所有我能实现的方法地址压入堆栈．．．
并且在栈尾压入最后一个方法－－－将字符串＂我爱你，你爱我吗？＂传递给你．．．
如果返回值为真－－我将用尽一生去爱你．．．
否则－－我将释放掉所有系统资源
</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.dutor.net/index.php/2009/08/cpplize-confession/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>C++中的内存分配</title>
		<link>http://www.dutor.net/index.php/2009/06/cpp-mem-allocation/</link>
		<comments>http://www.dutor.net/index.php/2009/06/cpp-mem-allocation/#comments</comments>
		<pubDate>Wed, 24 Jun 2009 14:35:32 +0000</pubDate>
		<dc:creator>dutor</dc:creator>
				<category><![CDATA[之语言特性]]></category>
		<category><![CDATA[边走编程]]></category>
		<category><![CDATA[Cpp]]></category>
		<category><![CDATA[虚拟内存]]></category>

		<guid isPermaLink="false">http://www.dutor.net/?p=804</guid>
		<description><![CDATA[在C++程序中，有下面五"类"内存:
<ul>

<li>在栈上创建。在执行函数时，函数内局部变量的存储单元都在栈上创建，函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中，一般使用寄存器来存取，效率很高，但是分配的内存容量有限。</li>

	<li>从堆上分配，亦称动态内存分配。程序在运行的时候用malloc或new申请任意多少的内存，程序员自己负责在何时用free或delete来释放内存。动态内存的生存期由程序员自己决定，使用非常灵活。</li>

	<li>从静态存储区域分配。内存在程序编译的时候就已经分配好，这块内存在程序的整个运行期间都存在。例如全局变量，static变量。</li>

	<li>文字常量分配在文字常量区，程序结束后由系统释放。</li>

	<li>程序代码区。</li>
</ul>

]]></description>
			<content:encoded><![CDATA[<p>在C++程序中，有下面五&#8221;类&#8221;内存:</p>
<ul>
<li>在栈上创建。在执行函数时，函数内局部变量的存储单元都在栈上创建，函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中，一般使用寄存器来存取，效率很高，但是分配的内存容量有限。</li>
<li>从堆上分配，亦称动态内存分配。程序在运行的时候用malloc或new申请任意多少的内存，程序员自己负责在何时用free或delete来释放内存。动态内存的生存期由程序员自己决定，使用非常灵活。</li>
<li>从静态存储区域分配。内存在程序编译的时候就已经分配好，这块内存在程序的整个运行期间都存在。例如全局变量，static变量。</li>
<li>文字常量分配在文字常量区，程序结束后由系统释放。</li>
<li>程序代码区。</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.dutor.net/index.php/2009/06/cpp-mem-allocation/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

