2010-07-28 104 views
4

在我们的应用,我们有其被定义为下面这样的队列:队列问题

private static Queue RawQ = new Queue(); 

然后两种不同类型的对象被放置到队列中,一个是从一类(class A)和一个是对象来自结构体的对象(struct B)。

当我们处理来自Queue的数据时,我们使用typeof来检查队列中属于哪个类型(A类或B类)的项目。

我的问题:

  1. 从A类对象,只有它们的引用复制到队列中,并从结构B对象,它们的值复制到队列,对吗?
  2. 对于队列,有些项目是小型参考,有些项目是更大的值(大约408字节)。如果Queue不小,这会浪费很多内存空间?
  3. 你有更好的方法来做同样的事情吗?

感谢,

回答

3

从A类对象,只有它们的引用复制到队列中,并从结构B对象,它们的值复制到队列,对吗?

正确。实际上,当你将一个结构B添加到队列中时,它首先被装箱。换句话说,您的B实例被复制到托管堆中,并且将对该副本的引用放在队列中。

对于一个队列,有些项目是小的参考,有些项目是更大的值(大约408字节)。如果Queue不小,这会浪费很多内存空间?

可能 - 装箱B实例需要一个副本,它使用更多的内存比不复制副本。这取决于原件发生了什么。

对于.NET结构,408个字节非常大;一般的经验法则是structs shouldn't be bigger than 16 bytes。原因与此类似:大型结构由于复制和装箱而引入开销。

你有更好的方法来做同样的事情吗?

我会问B是否需要首先是一个结构。另一个经验法则(这次是我的):你可能不需要在.NET代码中需要一个结构。

1

我试图仔细检查这一点,但这里是我相信的情况:

的System.Collections.Queue类持有Object类型的集合是引用类型。因此,当你将一个Struct的实例传递给你的队列时,它会被作为一个对象装箱。这会在堆上创建一个副本,并提供一个引用指针(这是队列所看到的)。所以,Queue本身并不会太大,但是如果你正在做很多这些操作,那么最终(根据微软),内存和性能会超过拳击/拆箱。

查看C# Language Specification了解更多信息。从A级

+0

是的,这是非常接近。 – 2010-07-28 17:40:05

2

1.对于对象,只有他们引用被复制到队列和 从结构B对象,它们的值 被复制到队列,对吗?

这是正确的。除了值类型会被装箱。

2.对于一个队列,某些项目,其是小的引用和一些 项目是它们是更大的值 (约408个字节)。这会浪费 很多内存空间,如果队列不是 很小?

这大部分是正确的。拳击将增加另外8个字节(4个用于同步块,4个用于类型信息),因此对于大型结构来说是微不足道的,但对于代表较大比例的较小结构。

3.你有更好的方法来做同样的事情吗?

最好的办法是将该大型结构转换为类。根据大小知道何时选择结构或类没有硬性规则,但是32个字节似乎是常见的阈值。当然,您可以根据您是否真的需要值类型语义来轻松证明较大的结构,但408字节可能超出该阈值。如果类型真的需要值语义,你可以使它成为一个不可变的类。

您可以进行的另一项更改是使用通用的Queue类。值类型不是像正常的Queue那样装箱。但是,即使使用通用版本,您仍然会复制该大型结构。

2

C# spec

由于结构不是引用类型, 这些操作的结构类型实施不同 。当结构类型的 值转换为 类型对象或由结构实现的接口类型 时,会发生 装箱操作。

因此,要回答1)队列包含盒装结构,而不是实际的结构值。

2)的答案不在此列,盒装结构和引用在队列的实际分配中具有相同的大小。

对于3),我需要更多的信息。最好在队列中拥有相同的类型,并且可以通过类和结构以适当的方式处理多态操作。过多的case语句和typeof()调用表明你的程序比面向对象更程序化。也许这就是你想要的,但是C#针对面向对象方法进行了优化。