C#Strings(和其他.NET API)的大小是否限制在2GB?

今天我注意到C#的String类将字符串的长度作为Int返回。 由于Int总是32位,无论架构如何,这是否意味着字符串的长度只能是2GB或更小?

一个2GB的字符串将是非常不寻常的,并伴随着它出现许多问题。 但是,大多数.NET api似乎都使用’int’来表示长度和计数等值。 这是否意味着我们永远受限于适合32位的集合大小?

似乎是.NET API的一个基本问题。 我希望通过相当于’size_t’的方式返回count和length之类的东西。

似乎是.NET API的一个基本问题……

我不知道我是否会走得那么远。

考虑几乎所有.NET中的集合类。 有可能它有一个返回intCount属性。 所以这表明该类的大小为int.MaxValue (2147483647)。 这不是一个真正的问题 ; 在绝大多数场景中,这是一个限制 – 而且是一个非常合理的限制

无论如何,替代方案是什么? 这是uint – 但这不符合CLS。 然后long ……

如果Length返回多long怎么办?

  1. 在您想知道字符串长度的任何地方都需要额外的32位内存。
  2. 好处是:我们可以让字符串占用数十亿GB的RAM。 万岁。

试着想象一下像这样的代码令人难以置信的代价:

 // Lord knows how many characters string ulysses = GetUlyssesText(); // allocate an entirely new string of roughly equivalent size string schmulysses = ulysses.Replace("Ulysses", "Schmulysses"); 

基本上,如果您认为string是一种旨在存储无限量文本的数据结构,那么您就会有不切实际的期望。 当涉及到这种大小的对象时,你是否需要将它们保存在内存中(而不是硬盘)会变得有问题。

正确,最大长度将是Int32的大小,但是如果你处理大于此的字符串,你可能会遇到其他内存问题。

在String.length()的某个值可能大约为5MB时,再也不能使用String了。 字符串针对短文本进行了优化。

想想你做什么会发生什么

 msString += " more chars" 

就像是:

系统计算myString的长度加上“更多字符”的长度

系统分配该内存量

系统将myString复制到新的内存位置

在最后复制myString char之后,系统将“更多字符”复制到新的内存位置

最初的myString受垃圾收集器的支配。

虽然这对于一小段文本而言很好而且整洁,但对于大字符串来说却是一场噩梦,只需要找到2GB的连续内存就可能是一个显而易见的事情。

因此,如果您知道处理超过几MB的字符,请使用其中一个* Buffer类。

你不太可能需要在一个集合中存储超过20亿个对象。 在进行枚举和查找时,您将会遇到一些非常严重的性能损失,这是集合的两个主要目的。 如果您正在处理的数据集很大,那么您可以采取其他一些路径,例如将您的单个集合拆分为许多较小的集合,这些集合包含您正在使用的整个数据集的部分。

Heeeey,等一下……我们已经有了这个概念 – 它被称为字典

如果你需要存储50亿英文字符串,请使用以下类型:

 Dictionary> bigStringContainer; 

让我们让关键字符串代表字符串的前两个字符。 然后写一个像这样的扩展方法:

 public static string BigStringIndex(this string s) { return String.Concat(s[0], s[1]); } 

然后将项添加到bigStringContainer,如下所示:

 bigStringContainer[item.BigStringIndex()].Add(item); 

并称它为一天。 (显然有更有效的方法可以做到这一点,但这只是一个例子)

哦,如果你确实真的需要能够通过绝对索引查找任意对象,请使用Array而不是集合。 好吧,是的,你使用了某种类型的安全性,但你可以用long索引数组元素。

框架使用Int32进行Count / Length属性,索引器等这一事实有点像红色鲱鱼。 真正的问题是CLR目前的最大对象大小限制为2GB。

所以string – 或任何其他单个对象 – 永远不会超过2GB。

更改string类型的Length属性以返回longulong甚至BigInteger都是没有意义的,因为无论如何你永远不会超过大约2 ^ 30个字符(每个字符最大2GB,每个字符2个字节)。

类似地,由于2GB限制,唯一可以接近具有2 ^ 31个元素的数组将是bool[]byte[]数组,每个元素仅使用1个字节。

当然,没有什么可以阻止你创建自己的复合类型来解决2GB限制。

(请注意,上述观察结果适用于Microsoft当前的实现,并且在将来的版本中可以很好地改变。我不确定Mono是否有类似的限制。)

在4.5之前的.NET版本中,最大对象大小为2GB。 从4.5开始,如果启用了gcAllowVeryLargeObjects,则可以分配更大的对象。 请注意, string的限制不受影响,但“数组”也应该涵盖“列表”,因为列表由数组支持。

即使在x64版本的Windows中,我也受到.Net的限制,将每个对象限制为2GB。

对于医学影像,2GB非常小。 对于Visual Studio下载映像,2GB甚至很小。

如果您正在使用2GB的文件,这意味着您可能会使用大量RAM,并且您看到的性能非常低。

相反,对于非常大的文件,请考虑使用MemoryMappedFile(请参阅: http : //msdn.microsoft.com/en-us/library/system.io.memorymappedfiles.memorymappedfile.aspx )。 使用此方法,您可以使用几乎无限大小的文件,而无需将整个内容加载到内存中。