关于拳击的问题

时间:2009-03-06 22:27:52

标签: c# boxing

我知道拳击是一个流行的概念,上面有大量的信息,但我有一些问题,我无法真正找到答案:

1)如果装箱导致将值类型(struct)转换为对象(引用类型)或引用类型,那么为什么要使用将被装箱并导致性能损失的值类型?我知道在结构或类的某些情况下的好处和适用性。据说(1)值(值类型)倾向于在临时存储空间中存在于堆栈中,但是多长时间?如果我不需要这种类型,我怎样才能确保在那一刻得到妥善处理?或者这是一次性模式发挥作用的地方?我认为使用结构的原因将归功于它的好处。

有趣的是,如果我使用struct来存储两个字符串和一个DateTime字段,那么struct将同时包含两个引用(字符串)和DateTime。我显然认为这比分散的值更快。在这个设计中有什么我需要注意的吗? (2)。

1)http://en.csharp-online.net/Classes, Structs, and Objects—Boxing and Unboxing

2)http://dotnetperls.com/Content/Struct-Examples.aspx

我在这里搜索了我追求的答案,但没有运气。我经常在这个网站上搜索GC,泛型,异常处理等主题,因为有很多学习和分享的智慧。

感谢所有海报的(潜在)教育!请原谅任何潜在的天真。学习内部结构很好地花了一些时间来理解IL等(很快就要解决的问题)。

4 个答案:

答案 0 :(得分:4)

如果您从未将值类型传递给引用变量,则不会发生装箱。如果您不知道,请回答以下questions

  • 像原始类型一样行事。
  • 实例大小不超过16个字节。
  • 是不可变的。
  • 值语义是可取的。

我通常也会考虑这样一个变量的生命周期。如果它是方法中使用的局部变量,那么我将使用struct(否则为class)。

答案 1 :(得分:1)

您应该使用值类型,因为它们的逻辑优势,而不是性能提升。话虽如此,因为值类型是在堆栈上管理的,所以不需要参与垃圾收集。如果你有一个不断创建和丢弃的类型(如int,float,double等),那么你可以通过将它们转换为结构来获得良好的提升。需要注意的是,如果你也可以使结构不可变,你应该只考虑这个。

答案 2 :(得分:1)

还需要考虑其他一些事项 -

首先,您要确保结构是不可变的(通常)。因此,没有包含引用类型的结构是一个很好的经验法则。字符串可以是一个例外,因为它们在C#中是不可变的,但就设计的通用经验法则而言,我会对此保持警惕。

第二,到目前为止还没有提到结构的另一个用例 - 大量小对象。如果你有一个大型列表或小型对象数组,结构提供了更好的缓存一致性,并且绝对是关键。这就是为什么大多数3D引擎都使用结构来表示点/向量 - 它们往往有大量的顶点点数等。

如果性能是您的应用程序的重要部分,这是值得注意的事项。例如,在我的一个应用程序中,将单个类型从类更改为结构,可以在长时间运行(> 5分钟运行时)过程中减少40%的折扣。如果在重度数学计算中重复使用它们,那么将对象放在内存中可以提供巨大的收益。

现在 - 在你的情况下,有2个字符串和一个DateTime可能不会看到任何改进。对字符串起作用的例程类型可能没有进行繁重的计算(希望如此),即:在空间中转换50万个点,或者进行大型矩阵解决方案等。

最后 - 你会注意到.net3.5sp1使结构更有用。在3.5sp1之前(在x86上),没有使用struct调用的内联方法。这限制了结构可能带来的性能提升。更新框架可以使旧的结构代码更快,更快(在某些情况下)。

答案 3 :(得分:0)

你并不总是需要拳击,而且对于普通而言,几乎不需要拳击 值类型使用的内存(struct是值类型)将声明为
一旦方法结束/返回,你就不需要为此发生任何事情。

声明为实例成员的值类型将在内存中直到对象
由GC删除。

引用类型保留在托管堆上 在方法中实例化的引用类型将被删除 没有对象持有引用的垃圾收集器。

GC独立工作,大多数情况下你应该不管它 您无法预测GC何时将删除对象。

Dispose模式用于参考类型,但不会强制GC删除
一个东西。它通常用于释放非托管资源。

对于堆栈中的值,请考虑以下内容:
假设您有一个简单的程序,有三种方法,如下所示:
运行此程序时,将运行Main方法,依此类推。请按照
以下数字:


Main
{
   // (0) Stack is empty
   int firstInt = 0;
   // (1) Stack now contains:
   //                     firstInt
   DoSomething1();
   // (7) Stack still contains:
   //                     firstInt
}
// Program ends

DoSomething()
{
   int anInteger = 0; 
   // (2) Stack now contains:
   //                    anInteger
   //                    firstInt
   DoMore()
   // (5) Stack now contains:
   //                     anInteger
   //                     firstInt
}
// (6) anInteger goes out of scope

DoMore
{
  int anotherInteger = 1; 
   // (3) Stack now contains:
   //                     anotherInteger
   //                     anInteger
   //                     firstInt
}
// (4) anotherInteger goes out of scope