夏虫不可语冰
此次事件讓我再次體會到了什么是“夏蟲不可語冰”。博客園有些人壓根沒看完你的文章,帶著已有認知斷章取義不暇思索上來就是噴。不過,以前也遇到過,現在也慢慢習慣了。
對于托管堆內存泄漏的說法,不管認不認同,我還是希望我的粉絲們能知道有這么個定義,有這么一回事。相信你們以后在閱讀文章或與人交流的時候,還會看到或聽到有人管這種現象叫內存泄漏,屆時也不至于蒙圈。雖然這是個很小的知識點。
C#中的匿名函數是頭等對象,可以作為變量使用,也可以作為參數傳遞。Task.Run 中使用匿名函數作為參數就是一個典型的應用場景。如果匿名函數捕獲了所在類的成員,對外部調用者來說,這個類的實例什么時候被釋放是無法預知的(除非你十分清楚這個類的內部實現),但你知道它最終是會被回收的。有人把這種可能導致對象延遲回收的現象定義為內存泄漏,也有很多人不認為是內存泄漏。這是定義問題,如果你能用一個詞來更好地定義這種現象也是可以接受的。
Many share the opinion that?managed memory leaks?are not memory leaks at all since they are still referenced and theoretically can be de-allocated. It’s a matter of definition and my point of view is that they are indeed?memory leaks. They hold memory that can’t be allocated for another instance and will eventually cause an out-of-memory exception.
Ref: dwz.date/d48U
很早之前我就看過類似的文章,把匿名方法捕獲類成員導致延遲回收的現象定義為內存泄漏。上面引用的這篇是最近閱讀到的一篇,這位外國作者寫了很多 .NET 內存管理相關的文章,都值得一讀。
如果只站在操作系統的角度看內存是否被掌控來定義內存泄漏,.NET 托管堆幾乎就沒有不被掌控的內存占用(托管堆之所以叫“托管”就是 CRL 會自動管理)。而之所以有人定義了托管內存泄漏,是因為對 CLR 來說,在局部視角不再需要使用的對象依然被其它實例引用,可能導致 GC 恰巧在搜索 Root 的時候不能把這個對象所占內存分配給其它實例。對于 CLR 來說,它對托管對象有全權“托管”之責。如果在被引用期間,恰巧 GC 在搜索 Root,就會導致 GC 錯過了一次回收該對象的機會,此次任務就“失職”了,只能在下一次搜索時回收它。但如果使用了本地(局部)變量,就可以避免這種情況。
大部分場景,我們并不需要在意這一點性能,何況這是個概率很低的事件。但是它值得引起注意,哪怕只有萬分之一的概率。在一些特別的場景下(比如高并發),遇到這個問題我們需要知道使用本地變量來優化我們的程序。
這個現象是不是內存泄漏,只是個定義問題,如果覺得這個定義不妥,可以不認同這個定義。正如 @楚人Le 說的,你也可以把它定義為“空間泄漏”:
我傾向于認為這屬于內存泄漏。Wikipedia上關于Memory leak有這樣一句話:“A space leak occurs when a computer program uses more memory than necessary. In contrast to memory leaks, where the leaked memory is never released, the memory consumed by a space leak is released, but later than expected”。如果我們非常較真的話,或許可以使用“空間泄露”這個詞。當計算機程序使用超過所需的內存時,就會發生空間泄漏。與內存泄漏相比,空間泄漏所消耗的內存會被釋放,但會比預期的要晚。
這只是個定義,這只是個定義,這只是個定義。不必糾結,更沒必要因為不認同就惡語相向。
今天的文章夾雜著一點情緒,請大家見諒。要說一點都不在意那些評論,那肯定是假的,心中多少還是會有些不愉悅的。面對網絡噴子,如果內心不夠強大,還真是不敢隨便發表文章。這次也讓我意識到,以后有爭議性的文章少寫,大家也是一樣。
自媒體很多大V都經歷過這種時段,和他們相比我這個蝦兵小卒遇到的這么三兩次不算什么。正如一線碼農大佬說的,有忠粉就有黑粉。既然走上這條路,必然也要經歷這些,這便是成長。
每每遇到這種事情,就特別想和鐵粉們說聲:感謝!感謝你們一路以來的陪伴、理解、支持和鼓勵,感謝你們愿意和我一起學習和成長。
總結
- 上一篇: 微软用的工具,统一财务三大表及高级分析通
- 下一篇: TVP两周年:携手同行,让未来可见