C#内存管理优化畅想(三)----其他方法&结语

11/25/2015来源:ASP.NET技巧人气:2861

前两篇文章提出的优化方法,都是不需要修改源代码的,而是在CLR或JIT层面进行自动优化的。但本文中提出的优化方法则需要引入新的语法,开发者只有在源代码中使用了这些新语法,才会获得优化。

1. 允许对象“嵌入式”组合:说白了,就是允许一个对象包含其他对象(包含的是对象本身,而非其引用),这样就把多个对象合并成了一个对象,减少了对象的数量,自然GC的压力就轻了。被包含的对象其实就相当于一个结构体(struct),禁止持有其引用。如果被包含对象是数组,至少应允许固定长度的情况,至于是否允许变长,则要看实现的难易程度了。

相关英文贴:

https://github.com/dotnet/roslyn/issues/2097

https://github.com/dotnet/roslyn/issues/6055

 

2. 把弱引用“升级”为语言特性,而不是作为一个类(为了兼容,原来的弱引用类也要保留)。目前的弱引用实现是CLR内部维护了长短两个弱引用表来记录弱引用,这样做似乎没有必要,而且引入了额外的开销,令使用者有所顾虑。既然GC之后CLR能够正确地更新本轮没被回收的对象的(强)引用,那么按理说也能更新本轮已被回收的对象的弱引用,并不需要额外的弱引用表,至少短弱引用是这样。如果能打消使用者的顾虑,使他们更近大胆地使用弱引用记录缓存,使用得当的话也是能给减轻GC的压力的。

相关英文贴:

https://github.com/dotnet/roslyn/issues/2171

 

3.  引入“引用计数”来辅助GC。可以让CLR针对开发者指定的类来维护其实例的引用计数,有了引用计数,可以实现两方面的优化。一是“写时复制”,即带有值类型特点的对象(类似string)可以被多处引用,只要不修改,就可以共享内存,而在修改时若引用计数为1则直接就地修改,若引用计数大于1,则先复制再修改复制的新对象。二是提前执行终结器,一旦某个对象的引用计数变为0,则立即执行其终结器函数(如果有的话),等到GC时即可直接回收其内存而无须再执行终结器,这就避免了终结器拖慢GC的积弊。当引用计数为0且无终结器时倒不是必须立即回收对象,因为这样做将在下次GC之前造成内存碎片,降低分配新对象的速度,有得有失,可以作为一个可选特性由使用者决定是否立即回收。

相关英文贴:

https://github.com/dotnet/coreclr/issues/1792

 

结语:到此为止,我所能想到的内存优化方法已经全部写完了,如果读者有更好的办法或者认为我的办法有缺陷,欢迎在评论中指出。