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中的集合类。 有可能它有一个返回int
的Count
属性。 所以这表明该类的大小为int.MaxValue
(2147483647)。 这不是一个真正的问题 ; 在绝大多数场景中,这是一个限制 – 而且是一个非常合理的限制 。
无论如何,替代方案是什么? 这是uint
– 但这不符合CLS。 然后long
……
如果Length
返回多long
怎么办?
- 在您想知道字符串长度的任何地方都需要额外的32位内存。
- 好处是:我们可以让字符串占用数十亿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
属性以返回long
, ulong
甚至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 )。 使用此方法,您可以使用几乎无限大小的文件,而无需将整个内容加载到内存中。