如何确定c#中非托管数组的大小?

本文关键字:数组 何确定 | 更新日期: 2023-09-27 18:15:52

我正在尝试优化一些代码,其中我有大量包含不同大小结构体的数组,但基于相同的接口。在某些情况下,结构体更大,容纳更多的数据,有时它们是小结构体,有时我更愿意保留null作为值以节省内存。

我的第一个问题是。这样做是个好主意吗?我以前有一个完整数据结构的数组,但是当测试混合它时,我实际上能够节省大量内存。还有其他缺点吗?

我一直在尝试不同的东西,它似乎工作得相当好,当一个公共接口的数组,但我不确定我检查数组的大小正确。

将示例简化了一些。但这里我要向数组中添加不同的结构体。但我无法用传统的Marshal来确定尺寸。运算符的方法。简单地遍历集合并计算集合中每个值的sizeof是正确的吗?

IComparable[] myCollection = new IComparable[1000];
myCollection[0] = null;
myCollection[1] = (int)1;
myCollection[2] = "helloo world";
myCollection[3] = long.MaxValue;
System.Runtime.InteropServices.Marshal.SizeOf(myCollection);

最后一行将抛出这个异常:

Type 'System.IComparable[]' cannot be marshaled as an unmanaged structure; no meaningful size or offset can be computed.

请原谅我的长篇大论:

  1. 这是一个最佳的和可用的解决方案吗?
  2. 我如何确定尺寸我的数组?

如何确定c#中非托管数组的大小?

我可能是错的,但它看起来像我你的IComparable[]数组是一个托管数组?如果是,那么您可以使用此代码来获取长度

int arrayLength = myCollection.Length;

如果你正在做c#和c++之间的平台互操作,那么你的问题标题"我能找到一个非托管数组的长度"的答案是否定的,这是不可能的。c++/C中带有数组的函数签名倾向于遵循以下模式

void doSomeWorkOnArrayUnmanaged(int * myUnmanagedArray, int length) 
{
    // Do work ...
} 

在。net中,数组本身是一种具有一些基本信息的类型,例如它的大小,运行时类型等。因此我们可以使用

void DoSomeWorkOnManagedArray(int [] myManagedArray) 
{
    int length = myManagedArray.Length; 
    // Do work ...
} 

无论何时使用平台调用在c#和c++之间进行互操作,您都需要将数组的长度传递给接收函数,以及固定数组(但这是另一个主题)。

这回答你的问题了吗?如果没有,请说明

最优性总是取决于您的需求。如果您确实需要存储不同类/结构的许多元素,您的解决方案是完全可行的。

然而,我猜你对数据结构的期望可能会误导:数组元素每个定义都具有相同的大小。甚至在您的例子中也是如此:您的数组并不存储元素本身,而是存储对它们的引用(指针)。这些元素被分配到VM堆的某个地方。所以你的数据结构实际上是这样的:它是一个包含1000个指针的数组,每个指针都指向一些数据。当然,每个特定元素的大小可能不同。

这引出了下一个问题:数组的大小。你打算怎么处理这个尺寸?当您将数据序列化到某个持久存储时,您需要知道分配多少字节吗?这取决于序列化格式…或者您只需要粗略估计一下您的结构消耗了多少内存?在后一种情况下,您需要考虑数组本身和每个特定元素的大小。您在示例中给出的数组消耗大约是引用大小的1000倍(在32位机器上应该是4字节,在64位机器上应该是8字节)。要计算每个元素的大小,实际上可以遍历数组并对特定元素的大小求和。请注意,这只是一个估计:虚拟机增加了一些内存管理开销,很难准确确定…