(1)限定被相似的名稱隱藏的成員 (2)將對象作為參數(shù)傳遞到其他方法 (3)聲明索引器 this指代類對象本身,用于訪問本類的所有常量、字段、屬性和方法成員,而且不管訪問元素是任何訪問級別。因為,this僅僅局限于對象內部,對象外部是無法看到的,這就是this的基本思想。另外,靜態(tài)成員不是對象的一部分,因此不能在靜態(tài)方法中引用this。
垃圾收集器以自己的線程運行,從程序里移除未
使用的內存,每次運行時也壓縮托管堆。通過壓縮堆,將托管堆里面的活動對象進行移動,可以使得空閑空間集中在一個連續(xù)的內存塊里。圖2.1 展示了堆的在垃圾收集前和垃圾收集后的2個快照。在每次GC進行操作后,所有的自由內存都集中在一個連續(xù)的塊里面。
<!--[if !vml]--><!--[endif]-->
Figure 2.1 垃圾收集器不僅移除未
使用的內存,而且也移動內存里的其它對象,并對是已經(jīng)
使用的內存進行壓縮,從而使得自由空間最大化。
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:
正如你剛學到的一樣,內存管理完全是垃圾收集器的職責,管理所有其它的系統(tǒng)資源則是你的職責。你可以通過在類型內定義終結器來保證釋放其它系統(tǒng)資源。在一個已經(jīng)成為垃圾的對象從內存中移除之前,終結器會被調用。你能夠并且應該
使用這些方法來釋放對象擁有的任何未托管的資源。一個對象,在它成為垃圾后、系統(tǒng)重新獲得它的內存前,它的終結器會在某個時候被調用。這個非確定的終結過程意味著,你不能控制下面2者之間的關系:何時停止
使用一個對象,它的終結器何時被執(zhí)行。從C++來說,這是一個巨大的改變,使你的設計也有了重要的分歧。有經(jīng)驗的C++程序員編寫了這樣的類:在構造函數(shù)里面分配了關鍵的資源,在析構函數(shù)里面進行了釋放;
// 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環(huán)境或者C#語言的一部分。試圖強制將已經(jīng)習慣的C++的確定性終結方式用到C#語言中,不能很好的工作。在C#里面,終結器是逐漸執(zhí)行的,但是它不是及時執(zhí)行的。在前面的例子里,代碼逐漸的從關鍵區(qū)域退出,但是在C#里面,當方法退出時,它并不退出關鍵區(qū)域。退出關鍵區(qū)域的行為在以后的某個未知時間發(fā)生。你不知道是什么時候,你不可能知道。
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發(fā)現(xiàn)一個對象成了垃圾又要求進行終結時,還不能從內存中移除它。首先,它調用了終結器。執(zhí)行終結器的線程和收集垃圾的線程不是同一個。相反,GC將每個準備要終結的對象放在一個隊列里面,生成另一個線程來執(zhí)行所有的終結器。GC繼續(xù)自己的工作:從內存中移除其它垃圾。在下一輪的垃圾收集周期內,這些已經(jīng)被終結的對象才被從內存里移除。圖 2.2 展示了3個不同的GC操作,以及它們在內存上的不同。注意,要求終結器的對象會在內存中多停留一個額外的周期。
<!--[if !vml]--><!--[endif]-->
這個序列展示了終結器作用在垃圾收集器上的效果。對象會在內存里停留更長,一個額外的線程需要被生成來執(zhí)行垃圾收集器。
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(世代)來優(yōu)化自己的工作。Generations幫助GC更快的定義最可能的垃圾候選者。在執(zhí)行最近的垃圾收集操作時,任何被創(chuàng)建的對象,都是第0代對象。任何經(jīng)歷了一次GC操作的對象是第1代對象。任何經(jīng)歷了2次或更多GC操作的對象是第2代對象。分代的目的是:分離局部變量和生命期貫穿整個程序的對象。第0代對象絕大多數(shù)是局部變量,成員變量和全局變量迅速的成為第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優(yōu)化了自己的工作。每個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.
作為總結,記住:垃圾收集器對內存管理負責的托管環(huán)境是一個很重要的附加物,內存泄露和其它和指針相關的陷阱問題,將不再是你的問題。非內存資源強迫你創(chuàng)建終結器來保證對這些它們進行合適的清理。終結過程對你的程序性能有深刻的影響,但是必須要編寫這些來避免資源泄漏。實現(xiàn)、
使用IDisposable接口避免了引入終結器的在垃圾收集器上帶來的性能負擔。下一節(jié)將進入詳細的條款,會幫助你創(chuàng)建更高效
使用該環(huán)境的程序。