c# – 具有超过65535 ^ 2个元素的2d-Array – >数组维度超出了支持的范围

c# – 具有超过65535 ^ 2个元素的2d-Array – >数组维度超出了支持的范围,第1张

概述我有一台带有128 GB RAM的64位PC,我正在使用C#和.NET 4.5. 我有以下代码: double[,] m1 = new double[65535, 65535];long l1 = m1.LongLength;double[,] m2 = new double[65536, 65536]; // Array dimensions exceeded supported rang 我有一台带有128 GB RAM的64位PC,我正在使用C#和.NET 4.5.
我有以下代码:

double[,] m1 = new double[65535,65535];long l1 = m1.LongLength;double[,] m2 = new double[65536,65536]; // Array dimensions exceeded supported rangelong l2 = m2.LongLength;

我知道< gcallowverylargeobjects enabled =“true”/>我把它设置为真.

为什么多维数组不能超过4294967295个元素
我看到以下答案https://stackoverflow.com/a/2338797/7556646.

我检查了gcAllowVeryLargeObjects的文档,我看到了以下注释.

The maximum number of elements in array is 07002 (4294967295).

我不明白为什么有这个限制?有解决方法吗?是否计划在即将推出的.net版本中删除此限制?

我需要在存储器中的元素,因为我想计算例如使用英特尔MKL的对称特征值分解.

[Dllimport("custom_mkl",CallingConvention = CallingConvention.Cdecl,ExactSpelling = true,SetLastError = false)]internal static extern lapack_int LAPACKE_dsyevd(    int matrix_layout,char jobz,char uplo,lapack_int n,[In,Out] double[,] a,lapack_int lda,Out] double[] w);
解决方法 免责声明:这个结果比预期更长

为什么CLR不支持大型数组

CLR不支持托管堆上的大型数组有多种原因.

其中一些是技术性的,其中一些可能是“范式的”.

这个blog post涉及到为什么存在限制的一些原因.基本上,由于内存碎片,决定限制(大写O)对象的最大大小.实现处理较大对象的成本与这样一个事实进行权衡,即在大多数情况下,由于程序员的设计谬误,需要这样大的对象和那些需要大量对象的用例.
因为,对于CLR,一切都是对象,这个限制也适用于数组.为了强制实施此限制,数组索引器采用带符号整数设计.

但是一旦你确定,你的程序设计要求你有这么大的阵列,你将需要一个解决方法.

上面提到的博客文章还表明,您可以实现大型数组而无需进入非托管区域.

但正如Evk在评论中指出的那样,你想通过PInvoke将数组作为一个整体传递给外部函数.这意味着您将需要非托管堆上的数组,或者它必须在调用期间进行封送处理.整个事情的编组是一个坏主意,这个数组很大.

解决方法

因此,由于托管堆是不可能的,因此您需要在非托管堆上分配空间并将该空间用于您的阵列.

假设您需要8 GB的空间:

long size = (1L << 33);IntPtr basePointer = System.Runtime.InteropServices.Marshal.AllocHGlobal((IntPtr)size);

大!现在,您在虚拟内存中有一个区域,您可以在其中存储最多8 GB的数据.

如何将其转换为数组?

那么C#有两种方法

“不安全”的方法

这将让你使用指针.指针可以转换为数组. (在香草C中它们通常是同一个)

如果您对如何通过指针实现2D阵列有一个好主意,那么这将是您的最佳选择.

这是pointer

“元帅”方法

您不需要不安全的上下文,而是必须将您的数据从托管堆“编组”到非托管堆.你仍然需要理解指针算术.

您要使用的两个主要功能是PtrToStructure和反向StructureToPtr.使用一个您将获得非托管堆上指定位置的值类型(例如双精度)的副本.使用另一个,您将在非托管堆上放置值类型的副本.

从某种意义上说,这两种方法都是“不安全的”.你需要知道你的pointers

常见陷阱包括但不限于:

>忘记严格检查边界
>混合我的元素的大小
>弄清楚对齐方式
>混合你想要的2D阵列
>忘记使用2D数组进行填充
>忘记释放记忆
>忘记释放内存并使用它无论如何

您可能希望将2D阵列设计转换为一维阵列设计

在任何情况下,您都希望将其全部包含在具有相应检查和destsructors的类中.

灵感的基本例子

接下来是基于非托管堆的“类似”数组的泛型类.

特色包括:

>它有一个接受64位整数的索引访问器.
>它限制了T可以成为值类型的类型.
>它有一定的检查和一次性.

如果你注意到,我没有进行任何类型检查,所以如果Marshal.SizeOf无法返回正确的数字,我们就会落入上面提到的一个坑中.

您必须自己实现的功能包括:

> 2D Accessor和2D Array算法(取决于其他库所期望的,通常它类似于p = x * size y
>用于PInvoke目的的暴露指针(或内部调用)

因此,只使用它作为灵感,如果有的话.

using static System.Runtime.InteropServices.Marshal;public class LongArray<T> : Idisposable where T : struct {    private IntPtr _head;    private Int64 _capacity;    private UInt64 _bytes;    private Int32 _elementSize;    public LongArray(long capacity) {        if(_capacity < 0) throw new ArgumentException("The capacity can not be negative");        _elementSize = SizeOf(default(T));        _capacity = capacity;        _bytes = (ulong)capacity * (ulong)_elementSize;        _head = AllocHGlobal((IntPtr)_bytes);       }    public T this[long index] {        get {            IntPtr p = _getAddress(index);            T val = (T)System.Runtime.InteropServices.Marshal.PtrToStructure(p,typeof(T));            return val;        }        set {            IntPtr p = _getAddress(index);            StructuretoPtr<T>(value,p,true);        }    }    protected bool disposed = false;    public voID dispose() {        if(!disposed) {            FreeHGlobal((IntPtr)_head);            disposed = true;        }    }    protected IntPtr _getAddress(long index) {        if(disposed) throw new ObjectdisposedException("Can't access the array once it has been disposed!");        if(index < 0) throw new IndexOutOfRangeException("Negative indices are not allowed");        if(!(index < _capacity)) throw new IndexOutOfRangeException("Index is out of bounds of this array");        return (IntPtr)((ulong)_head + (ulong)index * (ulong)(_elementSize));    }}
总结

以上是内存溢出为你收集整理的c# – 具有超过65535 ^ 2个元素的2d-Array – >数组维度超出了支持的范围全部内容,希望文章能够帮你解决c# – 具有超过65535 ^ 2个元素的2d-Array – >数组维度超出了支持的范围所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/langs/1233103.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-06
下一篇 2022-06-06

发表评论

登录后才能评论

评论列表(0条)

保存