过去几周,我一直在写一系列文章,来讨论创建.Net Compact Framework CLR时不同的设计结果是如何作出的。在第一章中,我讨论影响设计的环境因素,并提供CLR内存管理的概述。下面几章我们将详细讨论JIT编译器、垃圾回收和类装入器的主要设计思路,还有分析Compact Framework 应用程序内存使用的信息。
贯穿这个系列,我将着重讨论创建Compact Framework CLR时的设计决定,这些设计与.Net Framework CLR的设计有很大不同。
---------
表面上看起来,.Net Compact Framework是微软.Net Framework运行时环境的一个直接移植。但在设计的层次上,这两个产品的相似其实是有意为之,因为这样会提供相当的好处。Compact Framework和.Net Framework有相同的编程模型,使用相同的文件格式,共享相同的编译器等等。两个编程环境如此相似的主要好处是,开发者只要学习一个编程环境,就可以方便地在另一个环境上编程。例如,如果开发者熟悉.Net Framework,他几乎不需要花时间就可以学会使用.Net Compact Framework开发设备应用程序。
无论表面是如何类似,当你深入内部,你就会发现Compact Framework的实现,尤其是CLR组件,与桌面版本的实现完全不同。无须惊讶,Compact Framework的运行环境直接影响着它内部关键组件的架构。两个主要的环境因素影响了Compact Framework CLR的设计,第一是CLR需要运行在少量的内存环境中,第二是需要方便地跨越处理器和操作系统。
这个系列文章,通过了解对设计产生影响的约束条件,来讨论CLR的内部工作机制。通过这个系列我将指出CLR的哪些设计做了不同于桌面版本的修改,使托管代码能够运行在内存受限的环境中。
理解CLR的内部机制看起来是一个深奥的话题,但是对于你程序下面的平台如何工作有一个清晰的了解,会帮助你理解你的应用程序是如何使用设备的资源,也会帮你判断内存管理或性能相关的问题。
Compact Framework运行在许多不同的操作系统上,但是大部分是安装在Windows CE上的。让我们首先来了解一下Windows CE的内存机制。理解操作系统提供给Compact Framework的服务,将帮助我们理解Compact Framework团队在构建CLR时所作出的决定。
作为一个32位操作系统,Windows CE可以寻址4GB的虚拟地址空间,这方面和桌面版Windows是一致的。事实上,内存空间的划分对于Windows CE应用程序架构是有直接影响的。为了解决Windows CE应用程序访问内存的问题,每个应用程序只能操作32MB的虚拟地址空间。内存可以被分配到这32MB空间之外,但是这些内存是设备上所有应用程序共享的,这些分配的内存不是应用程序私有的。我们在这里只对Windows CE的内存模型进行一个简单介绍,使我们能够理解Compact Framework是如何访问内存的。关于Windows CE内存模型更详细的描述可以参考Doug Boling的《Programming Windows CE》(中文版名称《Windows CE程序设计》)。
下面的图描述了Windows CE应用程序可用的内存区域。
<shapetype id="_x0000_t75" stroked="f" filled="f" path="m@4@5l@4@11@9@11@9@5xe" o:preferrelative="t" o:spt="75" coordsize="21600,21600"><stroke joinstyle="miter"></stroke><formulas><f eqn="if lineDrawn pixelLineWidth 0"></f><f eqn="sum @0 1 0"></f><f eqn="sum 0 0 @1"></f><f eqn="prod @2 1 2"></f><f eqn="prod @3 21600 pixelWidth"></f><f eqn="prod @3 21600 pixelHeight"></f><f eqn="sum @0 0 1"></f><f eqn="prod @6 1 2"></f><f eqn="prod @7 21600 pixelWidth"></f><f eqn="sum @8 21600 0"></f><f eqn="prod @7 21600 pixelHeight"></f><f eqn="sum @10 21600 0"></f></formulas><path o:connecttype="rect" gradientshapeok="t" o:extrusionok="f"></path><lock aspectratio="t" v:ext="edit"></lock></shapetype><shape id="_x0000_i1025" style="WIDTH: 384pt; HEIGHT: 298.5pt" alt="" type="#_x0000_t75"><imagedata o:href="http://static.flickr.com/34/72969018_4dcda431c3_o.jpg" src="file:///C:/DOCUME~1/wolf/LOCALS~1/Temp/msoclip1/01/clip_image001.jpg"></imagedata></shape>
Figure 1
Memory available to Windows CE applications
正如我们所看到的,当程序运行时,会用到三个内存空间区域。
当程序运行时,.Net Compact Framework从这三个区域中获取需要的内存。正如我们所见,为了给托管应用程序的开发者提供最佳体验,Compact Framework管理每个进程的地址空间。
提高开发者生产力是促使.Net Framework和.Net Compact Framewok被广泛采用的主要原因。对于CLR提高开发者生产力的讨论经常围绕着自动内存管理(垃圾收集)、进程独立等话题展开。Compact Framework除了明确提供了这些功能外,也提供了更多帮助开发者提高移动设备程序开发生产力的更多功能。特别是.Net Compact Framework CLR代替开发者管理每个进程的32MB虚拟内存空间。所以开发者就不必为他们的程序在32MB空间中分配或释放内存而担心了。Compact Framework使编写内存受限设备上的应用程序变得简单。我们将看到,在这个系列文章中,许多构建.Net Compact Framework CLR的关键设计决定就是为了有效地管理每个进程32MB的虚拟内存空间。Windows CE将每个进程限制到一个小的虚拟地址空间中,而Compact Framework团队所要做的事情就是设计一个平台,让应用程序在给定的空间中运行得更好。
在描述允许在内存受限设备上的设计细节前,我们需要先来看一下,当执行一个托管程序时,操作系统和CLR创建的所有运行时数据。在我讨论完运行一个程序需要的数据种类后,我将告诉大家CLR会将哪些运行时数据分配到Windows CE的哪个内存区域中去。我们首先来考虑“Hello World”程序运行时,运行时数据的哪些种类需要内存。
using System;
using System.ComponentModel;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
namespace HelloDevice
{
public class Form1 : Form
{
private MainMenu mainMenu1;
private Label label1;
public Form1()
{
InitializeComponent();
}
private void InitializeComponent()
{
this.mainMenu1 = new System.Windows.Forms.MainMenu();
this.label1 = new System.Windows.Forms.Label();
// Position the label
this.label1.Location = new System.Drawing.Point(64, 81);
this.label1.Size = new System.Drawing.Size(100, 20);
this.label1.Text = "Hello Device!";
// Size the form
this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;
this.ClientSize = new System.Drawing.Size(240, 268);
this.Controls.Add(this.label1);
this.Menu = this.mainMenu1;
this.MinimizeBox = false;
this.Text = "Simple App";
}
}
static class Program
{
static void Main()
{
Application.Run(new Form1());
}
}
}
正如你所看到的,这个程序创建了一个带有“Hello Device!”字样的Label控件的窗体。我总结出该程序需要使用内存的六种情况。
现在我们可以看到运行托管程序需要用到的数据种类,让我们将它们映射回Windows CE内存模型中去。图2表示的就是每种运行时数据种类被存储到Windows CE内存的哪个区域中。
<shape id="_x0000_i1026" style="WIDTH: 384pt; HEIGHT: 333pt" alt="" type="#_x0000_t75"><imagedata o:href="http://static.flickr.com/35/72969019_5ef45cf904_o.jpg" src="file:///C:/DOCUME~1/wolf/LOCALS~1/Temp/msoclip1/01/clip_image002.jpg"><font size="3"></font></imagedata></shape>
Figure 2
The mapping between Compact Framework memory allocations and the Windows CE memory model.
根据图2,最重要的是了解哪些内存是分配在每个进程的空间中,而哪些是被所有进程共享。回到前边我们对Windows CE内存模型的讨论,我们知道,被加载到系统代码空间中的代码页和所有在高位内存地址空间上的内存分配都是被所有应用程序共享的,而在每个进程空间中的内存分配都是该进程私有的。因为进程中的分配不能共享,如何使用每个进程32MB的虚拟地址空间就是一个十分重要的事情。所以我们决定CLR将jitted代码、引用类型、in-memory type representations和其他小的内存分配都放在进程空间内。更多关于进程堆尺寸的信息可以参考Mike Zintel的Blog Advanced Compact Framework Memory Management。
现在我们讨论了基础话题,下一章我们将讨论.Net Compact Framework JIT编译器的一些基本设计思想。
This posting is provided "AS IS" with no warranties, and confers no rights.