分享

c#基础学习:base和this

 kairry 2010-10-20


垃圾收集器以自己的线程运行,从程序里移除未使用的内存,每次运行时也压缩托管堆。通过压缩堆,将托管堆里面的活动对象进行移动,可以使得空闲空间集中在一个连续的内存块里。图2.1 展示了堆的在垃圾收集前和垃圾收集后的2个快照。在每次GC进行操作后,所有的自由内存都集中在一个连续的块里面。

<!--[if !vml]--><!--[endif]-->

Figure 2.1 垃圾收集器不仅移除未使用的内存,而且也移动内存里的其它对象,并对是已经使用的内存进行压缩,从而使得自由空间最大化。

As you've just learned, memory management is completely the responsibility of the Garbage Collector. All other system resources are your responsibility. You can guarantee that you free other system resources by defining a finalizer in your type. Finalizers are called by the system before an object that is garbage is removed from memory. You can and mus tuse these methods to release any unmanaged resources that an object owns. The finalizer for an object is called at some time after it becomes garbage and before the system reclaims its memory. This nondeterministic finalization means that you cannot control the relationship between when you stop using an object and when its finalizer executes. That is a big change from C++, and it has important ramifications for your designs. Experienced C++ programmers wrote classes that allocated a critical resource in its constructor and released it in its destructor:

正如你刚学到的一样,内存管理完全是垃圾收集器的职责,管理所有其它的系统资源则是你的职责。你可以通过在类型内定义终结器来保证释放其它系统资源。在一个已经成为垃圾的对象从内存中移除之前,终结器会被调用。你能够并且应该使用这些方法来释放对象拥有的任何未托管的资源。一个对象,在它成为垃圾后、系统重新获得它的内存前,它的终结器会在某个时候被调用。这个非确定的终结过程意味着,你不能控制下面2者之间的关系:何时停止使用一个对象,它的终结器何时被执行。从C++来说,这是一个巨大的改变,使你的设计也有了重要的分歧。有经验的C++程序员编写了这样的类:在构造函数里面分配了关键的资源,在析构函数里面进行了释放;

// Good C++, bad C#:
class CriticalSection
{
public:
// Constructor acquires the system resource.
CriticalSection( )
{
EnterCriticalSection( );
}
// Destructor releases system resource.
~CriticalSection( )
{
ExitCriticalSection( );
}
};

// usage:
void Func()
{
// The lifetime of s controls access to
// the system resource.
CriticalSection s;
// Do work.
//...
// compiler generates call to destructor.
// code exits critical section.
}


This common C++ idiom ensures that resource deallocation is exception-proof. This doesn't work in C#, however at least, not in the same way. Deterministic finalization is not part of the .NET environment or the C# language. Trying to force the C++ idiom of deterministic finalization into the C# language won't work well. In C#, the finalizer eventually executes, but it doesn't execute in a timely fashion. In the previous example, the code eventually exits the critical section, but, in C#, it doesn't exit the critical section when the function exits. That happens at some unknown time later. You don't know when. You can't know when.

通常的C++习惯保证了资源的重分配是无异常的。这在C#里面是不能工作的,至少不是用同样的方式工作。确定性的终结过程不是.Net环境或者C#语言的一部分。试图强制将已经习惯的C++的确定性终结方式用到C#语言中,不能很好的工作。在C#里面,终结器是逐渐执行的,但是它不是及时执行的。在前面的例子里,代码逐渐的从关键区域退出,但是在C#里面,当方法退出时,它并不退出关键区域。退出关键区域的行为在以后的某个未知时间发生。你不知道是什么时候,你不可能知道。

Relying on finalizers also introduces performance penalties. Objects that require finalization put a performance drag on the Garbage Collector. When the GC finds that an object is garbage but also requires finalization, it cannot remove that item from memory just yet. First, it calls the finalizer. Finalizers are not executed by the same thread that collects garbage. Instead, the GC places each object that is ready for finalization in a queue and spawns yet another thread to execute all the finalizers. It continues with its business, removing other garbage from memory. On the next GC cycle, those objects that have been finalized are removed from memory. Figure 2.2 shows three different GC operations and the difference in memory usage. Notice that the objects that require finalizers stay in memory for extra cycles.

依赖于终结器也引来了性能上的损失。要求有终结过程的对象在性能上对垃圾收集器产生了拖累。当GC发现一个对象成了垃圾又要求进行终结时,还不能从内存中移除它。首先,它调用了终结器。执行终结器的线程和收集垃圾的线程不是同一个。相反,GC将每个准备要终结的对象放在一个队列里面,生成另一个线程来执行所有的终结器。GC继续自己的工作:从内存中移除其它垃圾。在下一轮的垃圾收集周期内,这些已经被终结的对象才被从内存里移除。图 2.2 展示了3个不同的GC操作,以及它们在内存上的不同。注意,要求终结器的对象会在内存中多停留一个额外的周期。

<!--[if !vml]--><!--[endif]-->

这个序列展示了终结器作用在垃圾收集器上的效果。对象会在内存里停留更长,一个额外的线程需要被生成来执行垃圾收集器。

This might lead you to believe that an object that requires finalization lives in memory for one GC cycle more than necessary. But I simplified things. It's more complicated than that because of another GC design decision. The .NET Garbage Collector defines generations to optimize its work. Generations help the GC identify the likeliest garbage candidates more quickly. Any object created since the last garbage collection operation is a generation 0 object. Any object that has survived one GC operation is a generation 1 object. Any object that has survived two or more GC operations is a generation 2 object. The purpose of generations is to separate local variables and objects that stay around for the life of the application. Generation 0 objects are mostly local variables. Member variables and global variables quickly enter generation 1 and eventually enter generation 2.

这可能导致你相信,一个要求进行终结的对象在内存里面要比必要的时间多生存一个GC周期。但是我刚才是将事情简化了。实际上要比这复杂的多,这是由另外一个GC设计决定的。.Net垃圾收集器定义Generations(世代)来优化自己的工作。Generations帮助GC更快的定义最可能的垃圾候选者。在执行最近的垃圾收集操作时,任何被创建的对象,都是第0代对象。任何经历了一次GC操作的对象是第1代对象。任何经历了2次或更多GC操作的对象是第2代对象。分代的目的是:分离局部变量和生命期贯穿整个程序的对象。第0代对象绝大多数是局部变量,成员变量和全局变量迅速的成为第1代,逐渐成为第2代。

The GC optimizes its work by limiting how often it examines first- and second-generation objects. Every GC cycle examines generation 0 objects. Roughly 1 GC out of 10 examines the generation 0 and 1 objects. Roughly 1 GC cycle out of 100 examines all objects. Think about finalization and its cost again: An object that requires finalization might stay in memory for nine GC cycles more than it would if it did not require finalization. If it still has not been finalized, it moves to generation 2. In generation 2, an object lives for an extra 100 GC cycles until the next generation 2 collection.

通过限制检查第1代和第2代对象的频率,GC优化了自己的工作。每个GC周期都检查第0代对象。粗略来看,1/10的GC会检查第0代和第1代对象,1/100的GC周期检查所有的对象。再次考虑终结器和它的代价:一个对象,要求了终结过程和没有的相比,可能在内存里面多驻留9个GC周期。如果它还没有被终结的话,就会被移入到第2代里面。在第2代里面,一个对象会生存额外的100个GC周期,直到下一轮对第2代的收集。

To close, remember that a managed environment, where the Garbage Collector takes the responsibility for memory management, is a big plus: Memory leaks and a host of other pointer-related problems are no longer your problem. Nonmemory resources force you to create finalizers to ensure proper cleanup of those nonmemory resources. Finalizers can have a serious impact on the performance of your program, but you must write them to avoid resource leaks. Implementing and using the IDisposable interface avoids the performance drain on the Garbage Collector that finalizers introduce. The next section moves on to the specific items that will help you create programs that use this environment more effectively.

作为总结,记住:垃圾收集器对内存管理负责的托管环境是一个很重要的附加物,内存泄露和其它和指针相关的陷阱问题,将不再是你的问题。非内存资源强迫你创建终结器来保证对这些它们进行合适的清理。终结过程对你的程序性能有深刻的影响,但是必须要编写这些来避免资源泄漏。实现、使用IDisposable接口避免了引入终结器的在垃圾收集器上带来的性能负担。下一节将进入详细的条款,会帮助你创建更高效使用该环境的程序。
 
base: 用于在派生类中实现对基类公有或者受保护成员的访问,但是只局限在构造函数、实例方法和实例属性访问器中。 MSDN中小结的具体功能包括:
    (1)调用基类上已被其他方法重写的方法。      (2)指定创建派生类实例时应调用的基类构造函数。
base常用于,在派生类对象初始化时和基类进行通信。  base可以访问基类的公有成员和受保护成员,私有成员是不可访问的。在多层继承中,base可以指向的父类的方法有两种情况:一是有重载存在的情况下,base将指向直接继承的父类成员的方法;而没有重载存在的情况下,base可以指向任何上级父类的公有或者受保护方法。 
this: 用于引用类的当前实例,也包括继承而来的方法,通常可以隐藏this。 MSDN中的小结功能主要包括:
    (1)限定被相似的名称隐藏的成员      (2)将对象作为参数传递到其他方法      (3)声明索引器  this指代类对象本身,用于访问本类的所有常量、字段、属性和方法成员,而且不管访问元素是任何访问级别。因为,this仅仅局限于对象内部,对象外部是无法看到的,这就是this的基本思想。另外,静态成员不是对象的一部分,因此不能在静态方法中引用this。 

通用规则
1、尽量少用或者不用base和this。除了决议子类的名称冲突和在一个构造函数中调用其他的构造函数之外,base和this的使用容易引起不必要的结果。  2、在静态成员中使用base和this都是不允许的。原因是,base和this访问的都是类的实例,也就是对象,而静态成员只能由类来访问,不能由对象来访问。  3、base是为了实现多态而设计的。  4、使用this或base关键字只能指定一个构造函数,也就是说不可同时将this和base作用在一个构造函数上。  5、简单的来说,base用于在派生类中访问重写的基类成员;而this用于访问本类的成员,当然也包括继承而来公有和保护成员。  6、除了base,访问基类成员的另外一种方式是:显示的类型转换来实现。只是该方法不能为静态方法。 

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多