第一個就是很多人用.Net寫程序,會談到托管這個概念。那么.Net所指的資源托管到底是什么意思,是相對於所有資源,還是只限於某一方面資源?很多人對此不是很了解,其實.Net所指的托管只是針對內存這一個方面,並不是對於所有的資源;因此對於Stream,數據庫的連接,GDI+的相關對象,還有Com對象等等,這些資源並不是受到.Net管理而統稱為非托管資源。而對於內存的釋放和回收,系統提供了GC-Garbage Collector,而至於其他資源則需要手動進行釋放。
那么第二個概念就是什么是垃圾,通過我以前的文章,會了解到.Net類型分為兩大類,一個就是值類型,另一個就是引用類型。前者是分配在棧上,並不需要GC回收;后者是分配在堆上,因此它的內存釋放和回收需要通過GC來完成。GC的全稱為“Garbage Collector”,顧名思義就是垃圾回收器,那么只有被稱為垃圾的對象才能被GC回收。也就是說,一個引用類型對象所占用的內存需要被GC回收,需要先成為垃圾。那么.Net如何判定一個引用類型對象是垃圾呢,.Net的判斷很簡單,只要判定此對象或者其包含的子對象沒有任何引用是有效的,那么系統就認為它是垃圾。
明確了這兩個基本概念,接下來說說GC的運作方式以及其的功能。內存的釋放和回收需要伴隨着程序的運行,因此系統為GC安排了獨立的線程。那么GC的工作大致是,查詢內存中對象是否成為垃圾,然后對垃圾進行釋放和回收。那么對於GC對於內存回收采取了一定的優先算法進行輪循回收內存資源。其次,對於內存中的垃圾分為兩種,一種是需要調用對象的析構函數,另一種是不需要調用的。GC對於前者的回收需要通過兩步完成,第一步是調用對象的析構函數,第二步是回收內存,但是要注意這兩步不是在GC一次輪循完成,即需要兩次輪循;相對於后者,則只是回收內存而已。
那么第二個概念就是什么是垃圾,通過我以前的文章,會了解到.Net類型分為兩大類,一個就是值類型,另一個就是引用類型。前者是分配在棧上,並不需要GC回收;后者是分配在堆上,因此它的內存釋放和回收需要通過GC來完成。GC的全稱為“Garbage Collector”,顧名思義就是垃圾回收器,那么只有被稱為垃圾的對象才能被GC回收。也就是說,一個引用類型對象所占用的內存需要被GC回收,需要先成為垃圾。那么.Net如何判定一個引用類型對象是垃圾呢,.Net的判斷很簡單,只要判定此對象或者其包含的子對象沒有任何引用是有效的,那么系統就認為它是垃圾。
明確了這兩個基本概念,接下來說說GC的運作方式以及其的功能。內存的釋放和回收需要伴隨着程序的運行,因此系統為GC安排了獨立的線程。那么GC的工作大致是,查詢內存中對象是否成為垃圾,然后對垃圾進行釋放和回收。那么對於GC對於內存回收采取了一定的優先算法進行輪循回收內存資源。其次,對於內存中的垃圾分為兩種,一種是需要調用對象的析構函數,另一種是不需要調用的。GC對於前者的回收需要通過兩步完成,第一步是調用對象的析構函數,第二步是回收內存,但是要注意這兩步不是在GC一次輪循完成,即需要兩次輪循;相對於后者,則只是回收內存而已。
那么對於程序資源來說,我們應該做些什么,以及如何去做,才能使程序效率最高,同時占用資源能盡快的釋放。前面也說了,資源分為兩種,托管的內存資源,這是不需要我們操心的,系統已經為我們進行管理了;那么對於非托管的資源,這里再重申一下,就是Stream,數據庫的連接,GDI+的相關對象,還有Com對象等等這些資源,需要我們手動去釋放。
如何去釋放,應該把這些操作放到哪里比較好呢。.Net提供了三種方法,也是最常見的三種,大致如下:
<!--[if !supportLists]-->1.
<!--[endif]-->析構函數;
<!--[if !supportLists]-->2.
<!--[endif]-->繼承IDisposable接口,實現Dispose方法;
<!--[if !supportLists]-->3.
<!--[endif]-->提供Close方法。
經過前面的介紹,可以知道析構函數只能被GC 來調用的,那么無法確定它什么時候被調用,因此用它作為資源的釋放並不是很合理,因為資源釋放不及時;但是為了防止資源泄漏,畢竟它會被GC 調用,因此析構函數可以作為一個補救方法。而Close 與Dispose 這兩種方法的區別在於,調用完了對象的Close 方法后,此對象有可能被重新進行使用;而Dispose 方法來說,此對象所占有的資源需要被標記為無用了,也就是此對象被銷毀了,不能再被使用。例如,常見SqlConnection這個類,當調用完Close方法后,可以通過Open重新打開數據庫連接,當徹底不用這個對象了就可以調用Dispose方法來標記此對象無用,等待GC回收。明白了這兩種方法的意思后,大家在往自己的類中添加的接口時候,不要歪曲了這兩者意思。
如何去釋放,應該把這些操作放到哪里比較好呢。.Net提供了三種方法,也是最常見的三種,大致如下:
<!--[if !supportLists]-->1.
<!--[if !supportLists]-->2.
<!--[if !supportLists]-->3.
經過前面的介紹,可以知道析構函數只能被GC 來調用的,那么無法確定它什么時候被調用,因此用它作為資源的釋放並不是很合理,因為資源釋放不及時;但是為了防止資源泄漏,畢竟它會被GC 調用,因此析構函數可以作為一個補救方法。而Close 與Dispose 這兩種方法的區別在於,調用完了對象的Close 方法后,此對象有可能被重新進行使用;而Dispose 方法來說,此對象所占有的資源需要被標記為無用了,也就是此對象被銷毀了,不能再被使用。例如,常見SqlConnection這個類,當調用完Close方法后,可以通過Open重新打開數據庫連接,當徹底不用這個對象了就可以調用Dispose方法來標記此對象無用,等待GC回收。明白了這兩種方法的意思后,大家在往自己的類中添加的接口時候,不要歪曲了這兩者意思。
GC為了提高回收的效 率使用了Generation的概念,原理是這樣的,第一次回收之前創建的對象屬於Generation 0,之后,每次回收時這個Generation的號碼就會向后挪一,也就是說,第二次回收時原來的Generation 0變成了Generation 1,而在第一次回收后和第二次回收前創建的對象將屬於Generation 0。GC會先試着在屬於Generation 0的對象中回收,因為這些是最新的,所以最有可能會被回收,比如一些函數中的局部變量在退出函數時就沒有引用了(可被回收)。如果在Generation 0中回收了足夠的內存,那么GC就不會再接着回收了,如果回收的還不夠,那么GC就試着在Genera
