gpt4 book ai didi

.net - 我如何知道可以分配给定类型的 .net 数组的实际最大元素数?

转载 作者:行者123 更新时间:2023-12-04 07:01:01 26 4
gpt4 key购买 nike

我知道 .net 中的所有数组都限制为 2 GB,在此前提下,我尽量不在数组中分配更多的 n = ((2^31) - 1)/8 双倍。尽管如此,这个数量的元素似乎仍然无效。任何人都知道如何在运行时确定给定 sizeof(T) 的最大元素数?

我知道接近这个数字的任何数量都只是很多元素,但是,出于所有意图和目的,假设我需要它。

注意:我在 64 位环境中,有一个用于我的 AnyCPU 应用程序的目标平台,并且 RAM 中至少有 3100 MB 可用空间。

更新:
谢谢大家的贡献,很抱歉我这么安静。对于给您带来的不便,我深表歉意。我无法重新表述我的问题,但我可以补充一点,我正在寻找的是解决这样的问题:

template <class T>
array<T>^ allocateAnUsableArrayWithTheMostElementsPossible(){
return gcnew array<T>( ... );
}

我自己的答案中的结果有点令人满意,但还不够好。此外,我还没有在另一台机器上测试它(很难找到另一台超过 4 GB 的机器)。此外,我一直在自己做一些研究,似乎没有便宜的方法可以在运行时计算它。无论如何,这只是一个加分项,我正在尝试完成的事情的用户都不能期望在没有能力的情况下使用我正在尝试实现的功能。

所以,换句话说,我只是想了解为什么在其他条件不变的情况下,数组的最大元素数加起来不等于 2GB。我现在只需要一个最高的最大值。

最佳答案

更新:答案完全重写。原始答案包含通过分而治之在任何系统上找到最大可能可寻址数组的方法,如果您有兴趣,请参阅此答案的历史。新答案试图解释 56 字节的差距。
his own answer , AZ 解释说,最大数组大小限制为小于 2GB 上限,并且通过一些试验和错误(或其他方法?)发现以下内容(摘要):

  • 如果类型的大小为 1、2、4 或 8 字节,则最大可占用大小为 2GB - 56 字节;
  • 如果类型的大小为 16 字节,则最大值为 2GB - 48 字节;
  • 如果类型的大小为 32 字节,则最大值为 2GB - 32 字节。

  • 我不完全确定 16 字节和 32 字节的情况。如果数组是结构数组或内置类型,则数组的总可用大小可能会有所不同。我将强调 1-8 字节的类型大小(我也不确定,见结论)。
    数组的数据布局
    了解为什么 CLR 不完全允许 ​​ 2GB / IntPtr.Size我们需要知道数组是如何构成的元素。一个好的起点是 SO article ,但不幸的是,有些信息似乎是错误的,或者至少是不完整的。这个 in-depth article on how the .NET CLR creates runtime objects被证明是无价的,还有这个 Arrays Undocumented CodeProject 上的文章。
    综合这些文章中的所有信息,可以归结为 32 位系统中的阵列的以下布局:
    Single dimension, built-in typeSSSSTTTTLLLL[...data...]0000^ sync block    ^ type handle        ^ length array                        ^ NULL 

    Each part is one system DWORD in size. On 64 bit windows, this looks as follows:

    Single dimension, built-in typeSSSSSSSSTTTTTTTTLLLLLLLL[...data...]00000000^ sync block        ^ type handle                ^ length array                                    ^ NULL 

    The layout looks slightly different when it's an array of objects (i.e., strings, class instances). As you can see, the type handle to the object in the array is added.

    Single dimension, built-in typeSSSSSSSSTTTTTTTTLLLLLLLLtttttttt[...data...]00000000^ sync block        ^ type handle                ^ length array                        ^ type handle array element type                                            ^ NULL 

    Looking further, we find that a built-in type, or actually, any struct type, gets its own specific type handler (all uint share the same, but an int has a different type handler for the array then a uint or byte). All arrays of object share the same type handler, but have an extra field that points to the type handler of the objects.

    A note on struct types: padding may not always be applied, which may make it hard to predict the actual size of a struct.

    Still not 56 bytes...

    To count towards the 56 bytes of the AZ's answer, I have to make a few assumptions. I assume that:

    1. the syncblock and type handle count towards the size of an object;
    2. the variable holding the array reference (object pointer) counts towards the size of an object;
    3. the array's null terminator counts towards the size of an object.

    A syncblock is placed before the address the variable points at, which makes it look like it's not part of the object. But in fact, I believe it is and it counts towards the internal 2GB limit. Adding all these, we get, for 64 bit systems:

    ObjectRef + 
    Syncblock +
    Typehandle +
    Length +
    Null pointer +
    --------------
    40 (5 * 8 bytes)
    还没到56。也许有人可以在调试期间查看 Memory View 以检查数组的布局在 64 位窗口下的样子。
    我的猜测是沿着这些思路(选择,混合和匹配):
  • 2GB 永远不可能,因为这是下一段的一个字节。最大的 block 应该是 2GB - sizeof(int) .但这很愚蠢,因为 mem 索引应该从零开始,而不是从一开始;
  • 任何大于 85016 字节的对象都将放在 LOH(大对象堆)上。这可能包括一个额外的指针,甚至是一个包含 LOH 信息的 16 字节结构。也许这算作极限;
  • 对齐:假设 objectref 不计算在内(无论如何它在另一个 mem 段中),总间隙为 32 个字节。系统很可能更喜欢 32 字节边界。重新审视内存布局。如果起始点需要位于 32 字节边界上,并且它需要为之前的同步块(synchronized block)提供空间,则同步块(synchronized block)将在前 32 字节 block 的末尾结束。像这样的东西:
      XXXXXXXXXXXXXXXXXXXXXXXXSSSSSSSSTTTTTTTTLLLLLLLLtttttttt[...data...]00000000
    在哪里 XXX..代表跳过的字节。
  • 多维数组:如果您使用 Array.CreateInstance 动态创建数组对于 1 个或多个维度,将使用两个额外的 DWORDS 创建一个单一的暗淡数组,其中包含维度的大小和下限(即使您只有一个维度,但前提是下限指定为非零)。我发现这不太可能,因为如果您的代码中出现这种情况,您可能会提到这一点。但这会使总开销达到 56 个字节;)。

  • 结论
    从我在这个小研究中收集到的所有信息中,我认为 Overhead + Aligning - Objectref是最可能和最合适的结论。然而,一位“真正的”CLR 大师或许能够对这个特殊的主题提供一些额外的启示。
    这些结论都没有解释为什么 16 或 32 字节数据类型分别具有 48 和 32 字节间隙。
    感谢一个具有挑战性的主题,在我的过程中学到了一些东西。当一些人发现这个新答案与问题更相关时,也许有些人可以取消投票(我最初误解了这一点,并为这可能造成的困惑道歉)。

    关于.net - 我如何知道可以分配给定类型的 .net 数组的实际最大元素数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1840481/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com