返回首页

介绍
的方式,以减少由应用程序使用的内存是修改应用程序的类和结构的定义,以便成为在内存较小的那些类型的实例。成千上万的实例类型,这可能会导致大量的储蓄。
通常情况下,虽然采取了常识性的方法,以减少对象的大小产生小于预期效益,有时会产生没有任何改善。由于这些优化可能需要相当长的时间来实施,使准确预测哪些变化是值得也很重要。
这篇文章解释了如何准确地计算出在内存占用特别优化,可从预计的改善,让您可以提前选择哪些优化将是值得的。当你应该费心?
在我介绍减少对象的大小背后的数学,我要开始的问题,ÄúShould你甚至不屑???因为在这篇文章中的技术,而偶尔必不可少的,经常是没有办法为您解决内存占用的问题。具体做法是:减少对象实例的大小将要取得的成果一般在每个实例的字节??,一般超过50个字节每个实例较少。所以,除非你知道你有很多的内存中的一个特定类型的实例,它一般是不值得与减少的情况下大小的困扰。ÄúHow即使你的内存分析器(或您自己的代码分析)已经确认,你有几千几万内存中的一个类型的实例,而不是开始的问题,我可以使每个实例???你应该开始,AUDO我需要在内存中的所有这些实例???有没有办法可以使其中一些可用于垃圾收集越早吗?或您可以使用Flyweight设计模式,以减少所需的实例数量?等等。
如果是,你必须在内存中一个可怕的很多,也没有,没有任何方式来获得大量的实例完全摆脱底线,然后在这篇文章中的信息可能会有所帮助。来源文章的信息/限制
这篇文章的大部分是直接基于实验证据,我从它派生的规则。因此,即使这篇文章解释了所有我获得的数据,它可能缺少各种精炼。我欢迎的改进,当然。计算一类或结构的大小?概述?
计算类或结构的实例(Äútarget类型??的大小是一个反复的过程,与System.Object的开始,和工作的继承链的目标类型(所有结构都直接源自。System.Object的)低于System.Object的继承链的每个环节,这里的是你的程序的大致轮廓,的Äôll按照 - 我,Äôll细节不久的数学很简单,但可以有时间。耗时长继承链和/或许多领域。确定一个基类的实例的大小。 确定的金额,Äúfree空间??内的基类的实例年底。确定多少实例(即非静态)当前类型的字段,将适合的自由空间内的基类。确定需要保持当前的类型不适合的自由空间在基类的实例字段的内存块的大小。从步骤4圆的数量是一个4字节的倍数。计算你所需要的两个结果: 你浑圆(即第5步减去步骤4)的数量是当前类型的可用空间量。例如,如果四舍五入从17到20个字节,有3个字节。数量四舍五入,再加上基类的大小(即第5步第1步),是当前类型的每个实例的大小。详情计算类或结构的大小?基类的特点步骤1和2??
这里的出发地点,这始终是相同的:System.Object的大小:12字节内每个System.Object的结束:4个字节的可用空间
,对于每类System.Object的其他可用空间的变化,从0-3个字节。
背后的想法是,Äúthe自由空间内的基类?类或结构的一个实例关联的大小将是一个4字节的倍数,但这个类里面的字段或结构不需要的所有空间。如果这个未使用的空间时,使用的内存类型,空间可以使用派生类的领域,从而减少了,否则将被派生类型的实例所需的空间。这种优化会自动进行,所有的时间,你必须意识到这一点的唯一的一次是当你在做各种计算。第3步??字段移动到基类的自由空间
(自动执行领域的重要说明:?所有这些讨论涉及计算的大小和在内存领域的安排,一定请记住一个属性没有明确支持领域,即使是是,它有,Äúset ??的,Äúget??存取,但没有定义的存取机构??它仍然有一个自动执行,无形的领域中,与物业相关的数据存储。当你,Äôre计数字段和字段大小,你需要这些领域也算。)
之前,我们可以谈,哪些领域可以移动到基类的自由空间,我们需要了解,在一般情况下,如何安排在内存中的一个类型的字段。
有三种基本方法,类或结构中的字段可以被安排在内存中,类的属性StructLayoutAttribute确定:LayoutKind.Sequential:默认情况下,这是使用StructLayoutAttribute值由结构。这种布局表明,在类型领域都奠定了在内存中,他们出现在类型定义的顺序相同,但间隔等,每场开始偏移字节(内型),是由大小整除该领域。例如,int和对象引用被放置在4个字节整除偏移(0,4,8,等等??也被称为??字节边界??,短裤和字符都放在2字节边界,字节和布尔可放置在任何位置(??字节边界??LayoutKind.Auto:默认情况下,这是由类使用StructLayoutAttribute价值。这种布局表明,在类型的字段可以由编译器在编译器喜欢的任何方式重新排序。为Microsoft C#编译器,这个领域的间隔使它们的字段大小(LayoutKind.Sequential)整除的字节边界下降,他们重新排序,使零间距结果,Äúdead空间的手段? ?字段之间。实际上,这是由放置在所有的8个字节的领域开始上课,由4个字节的领域,由2个字节的领域,其次是1字节的字段。有异常,AOS本灌装的自由空间,在基类的顺序,但我们,Äôll不久。LayoutKind.Explicit:这种布局是没有任何默认。使用一个明确的布局,你需要明确指定StructLayoutAttribute,然后为每个字段指定一个FieldOffset属性。这并不奇怪,所有的字段将被放置在您指定完全抵消。您可以使用此布局放置多个领域,在完全相同互相抵消,从而创造相当于旧的C工会的概念,但是从这个不起眼的能力之外,我没有发现任何方式使用此布局,以改善超越你能做到与其他两个布局的内存占用。 (有其他用途相关的数据编组,但这不是本文的主题。)因此,我不会在这篇文章中讨论此布局进一步。
对于确定哪些领域将移动的自由空间,在基类的目的,LayoutKind.Sequential和LayoutKind.Auto之间有一个很大的区别。
假设你有1个字节的自由空间,在基类。如果您的派生类使用LayoutKind.Auto,如果你有1个字节的字段,在派生类的序列领域的任何地方,编译器可以自由移动,1字节的字段的自由空间。如果您的派生类使用LayoutKind.Sequential,编译器可以利用1个字节的可用空间优势的唯一途径是,如果在派生类中的第一个字段是1字节的字段。
同样,如果基类有两个字节的可用空间,一个派生类使用LayoutKind.Auto优势,可以采取双方自由字节,如果它有一个2字节的字段,或两个1字节的字段,在任何地方领域的序列。如果类是LayoutKind.Sequential,它可以同时使用免费的字节的唯一途径是,如果第一个字段是一个2字节的领域,或前两个字段都是1个字节的领域。
因为编译器字节边界对齐字段的大小,要求完全使用3个字节的可用空间的倍数是一类使用LayoutKind.Sequential更加严格的领域。在这种情况下,只有两种方式来使用所有3个字节的可用空间:如果前三个字段是1字节的字段如果第一个字段是1字节的字段和第二个字段是一个2字节的领域
(2字节场由1字节的字段)的其他方式将无法填补所有的自由空间,因为第一场(2字节)将转移到可用的2个字节的边界,跳绳的第一个字节的可用空间,那么就会有第二的自由空间(1字节)字段没有留下房间。对于派生使用LayoutKind.Auto类的,所有需要使用所有可用空间是任何1个字节的三个领域,或任何1字节的字段加任何2字节的字段。第4步??须持有其余字段块大小
现在,我们已经决定持有其余领域所需的内存块的大小是确定哪些领域(如有),编译器将在基类中移动的自由空间,下一步是什么。 (好吧,我只是捏造,但只有一点点:中的LayoutKind.Auto的情况下,我们并不真正知道它的确切领域(S),编译器会移动,但它也不要紧,例如,当。填充2个字节的可用空间,它不会不管编译器将2个字节的某一特定领域,不同的2个字节的领域,或任何两个1字节的字段??数学是去上班了相同结束。)
对于LayoutKind.Auto,确定所需的内存块的大小是简单的编译器将安排在内存中剩余的领域,使它们之间没有死角。这意味着所需的内存块的大小仅仅是字段的大小。
LayoutKind.Sequential,计算所需的块大小是更多地参与,并且可以相当烦人。你开始的第一场,没有移动的自由空间的大小,然后寻找下一个字段的大小。使用的下一个字段的大小,以确定如何许多死角字节将需要添加到允许的第一场结束第二场,第二场的大小是一个多字节边界。总添加死角,并添加第二场总规模。然后重复:看第三场的大小,并确定如何死角多字节将需要增加,使之后的第二场第三场可以开始偏移,它的大小是一个多。新增的第二场的大小,AOS总死角,然后加总第三场的大小。等等,通过秩序中的所有领域。
这给我们带来的第一大,简单的方法来减少实例的大小。提示:如果一个struct使用LayoutKind.Sequential(默认),组织,使4字节字段来第一次,然后2个字节的字段,然后1字节的字段的字段声明。如果一个类被使用LayoutKind.Sequential,计算自由空间,可在基类和地方领域可以填补的自由空间。然后组织以同样的方式,你会为结构的其余字段:4字节的字段,然后2个字节的字段,然后1字节的字段

回答

评论会员: 时间:2
k