使用数组字段而不是大量的对象

时间:2011-07-10 06:19:15

标签: c# memory object storage field

鉴于this article,我想知道人们使用数组来存储大量数据集(例如,> 10,000,000个对象)的内存使用数据来存储数据字段而不是实例化数百万个对象并放弃内存开销(例如,每个对象12-24个字节,具体取决于您阅读的文章)。每个属性的数据因项目而异,因此我不能使用严格的Flyweight模式,但可以设想类似的东西。

我对这种表示的想法是,有一个'模板对象'......

class Thing
{
  double A;
  double B;
  int    C;
  string D;
}

然后是一个容器对象,其中包含一个根据请求创建对象的方法......

class ContainerOfThings
{
  double[] ContainerA;
  double[] ContainerB;
  int[]    ContainerC;
  string[] ContainerD;

  ContainerOfThings(int total)
  {
    //create arrays
  }

  IThing GetThingAtPosition(int position)
  {
     IThing thing = new Thing(); //probably best done as a factory instead
     thing.A = ContainerA[position];
     thing.B = ContainerB[position];
     thing.C = ContainerC[position];
     thing.D = ContainerD[position];

     return thing;
  }
}

所以这是一个简单的策略,但不是非常通用,例如,不能创建'Thing'的子集(作为List)而不重复数据并且无法实现阵列字段存储的目的。我一直无法找到好的例子,所以我很欣赏能够更好地处理这个场景的链接或代码片段来自那些已经完成它的人......或者更好的想法。

8 个答案:

答案 0 :(得分:5)

这取决于您的具体情况。取决于您创建对象的频率,您可以:

  1. 如果对象是可序列化的,请将它们保存在MemoryMappedFile中(获得一些中/低性能和低内存消耗的融合)。

  2. 映射不同对象之间的字段:我的意思是如果对象最初具有默认值,将它们全部放在单独的基础中,并且如果该值与默认值不同,则实际分配新空间。 (这自然适用于参考类型)。

  3. 另一个解决方案再次将对象保存到SqlLite库。比MemoryMappedFiles更容易管理,因为您可以使用简单的SQL。

  4. 选择取决于您,因为它取决于您对具体项目的要求。

    问候。

答案 1 :(得分:5)

  

根据这篇文章,我想知道人们使用数组存储大量数据集(例如,> 10,000,000个对象)来存储数据字段而不是实例化数百万个对象并增加内存开销的经验。 ..

我想有几种方法可以解决这个问题,实际上你正在寻找一种可能的解决方案来限制内存中的数据。但是,我不确定你的结构是否会减少到24? bytes会给你带来很多好处。你的结构大约是79个字节(15个字符串)= 8 + 8 + 4 + 24? + 4 + 1 +(2 *字符长度),因此您的总收益最多为25%。这似乎没有用,因为你必须处于1000万* 80字节适合内存而1000万* 100字节不适合的位置。这意味着你要设计一个处于灾难边缘的解决方案,太多的大字符串,或太多的记录,或其他一些程序占用内存,你的机器内存不足。

如果你需要支持n个小记录的随机访问,其中n = 1000万,那么你应该设计至少2n或10n。也许你已经考虑过你的1000万了?无论哪种方式,都有很多技术可以支持这种类型的数据被访问。

一种可能性是,如果字符串限制在最大长度(ml),合理的大小(比如255),那么你可以去一个简单的ISAM商店。每条记录将是8 + 8 + 4 + 255字节,您可以简单地偏移到平面文件中读取它们。如果记录大小可变或可能很大,那么您将需要使用不同的存储格式并将偏移存储到文件中。

另一种可能性是,如果您通过某个键查找值,那么我会推荐类似嵌入式数据库或BTree的东西,您可以禁用某些磁盘一致性以获得性能。碰巧我为大量数据的客户端缓存编写了一个BPlusTree。有关using the B+Tree are here的详细信息。

答案 2 :(得分:2)

实际上,ADO.NET DataTable使用类似的方法来存储数据。也许你应该看看它是如何实现的。 因此,您需要具有类似DataRow的对象,该对象在内部保存指向表和行数据索引的指针。这将是我认为最轻量级的解决方案。

在你的情况下: a)如果在每次调用GetThingAtPosition方法时构建Thing,则在堆中创建对象,这会使表中已有的信息加倍。加上“对象开销”数据。

b)如果您需要访问ContainerOfThings中的每个项目,则所需的内存将加倍+ 12bytes *对象开销数量。在这种情况下,最好有一个简单的事物阵列,而不是即时创建它们。

答案 3 :(得分:1)

您的问题意味着存在问题。内存使用量是否有问题?

如果每个项目100个字节,那么它听起来像1GB。所以我想知道应用程序,如果这是一个问题。该应用程序是否在专用的64位盒子上运行,例如8GB或ram?

如果有恐惧,你可以通过整合测试来测试恐惧。实例化说这些项目中有2000万个并运行一些性能测试。

但当然它确实都来自app域。我有专门的应用程序,使用比这更多的RAM,并且工作正常。硬件成本通常低于软件成本(再次归结为app域)。

见你

答案 4 :(得分:1)

不幸的是,OO无法抽象出性能问题(带宽饱和度为1)。这是一个方便的范例,但它有局限性。

我喜欢你的想法,我也使用它...猜猜看,我们不是第一个想到这个;-)。我发现它确实需要一点思维转变。

我可以向J社区介绍你吗?参见:

http://www.JSoftware.com

那不是C#(或Java)组。他们是一群很好的人。通常,数组需要被视为第一类对象。在C#中,它不是那么灵活。使用C#可能是一个令人沮丧的结构。

对于大型数据集问题有各种OO模式......但是如果你问这样的问题,可能是时候进行更多功能了。或至少可用于解决问题/原型设计。

答案 5 :(得分:1)

我为rapidSTORM项目做了这样的事情,需要缓存数百万个人口稀少的对象(本地化显微镜)。虽然我无法真正为您提供良好的代码片段(过多的依赖项),但我发现Boost Fusion的实现非常快速和直接。融合了结构,为每种元素类型构建了一个向量,然后为重建每个元素的向量写了一个非常简单的访问器。

(噢,我刚注意到你标记了这个问题,但也许我的C ++答案也有帮助)

答案 6 :(得分:1)

答案 7 :(得分:1)

使用类型中的每个属性创建一个System.Array数组。这些子数组的大小等于您拥有的对象数。物业访问将是:

masterArray [propertyIndex] [objectIndex]

这将允许您使用值类型数组而不是对象数组。