C# 在.NET4.0中共享内存的阵列-反射或StructLayout是否可以实现这一点?

C# 在.NET4.0中共享内存的阵列-反射或StructLayout是否可以实现这一点?,c#,arrays,reflection,.net-4.0,structlayout,C#,Arrays,Reflection,.net 4.0,Structlayout,我已经快速创建了巨大的瞬态阵列。有些是保留的,有些是GC-d。这会对堆进行碎片整理,应用程序消耗的内存约为实际所需内存的2.5倍,从而导致OutOfMemoryException 作为一个解决方案,我更愿意拥有一个巨大的数组(PointF[]),并自己分配和管理段。但我想知道如何使两个(或更多)阵列共享相同的内存空间 PointF[] giganticList = new PointF[100]; PointF[] segment = ???; // I want the segment le

我已经快速创建了巨大的瞬态阵列。有些是保留的,有些是GC-d。这会对堆进行碎片整理,应用程序消耗的内存约为实际所需内存的2.5倍,从而导致OutOfMemoryException

作为一个解决方案,我更愿意拥有一个巨大的数组(PointF[]),并自己分配和管理段。但我想知道如何使两个(或更多)阵列共享相同的内存空间

PointF[] giganticList = new PointF[100];
PointF[] segment = ???; 
// I want the segment length to be 20 and starting e.g at position 50 
// within the gigantic list
我在想一个技巧,就像答案的赢家。
那可能吗?问题是,段数组的长度和数量只有在运行时才知道。

您在这里的最佳选择可能是在相同的
点f[]
实例上使用多个
ArraySegment
,但偏移量不同,并让调用代码记下相对的
.Offset
Count
。请注意,您必须编写自己的代码来分配下一个块,并查找间隙等—本质上是您自己的迷你分配器

不能直接将这些段视为
PointF[]

因此:

PointF[]glanticlist=新的PointF[100];
//我希望段长度为20,从位置50开始
//在庞大的名单中
var段=新的排列段(巨Clist,50,20);

作为旁注:另一种方法可能是使用指向数据的指针-来自非托管分配,或者来自已固定的托管数组(注意:您应该尽量避免固定),但是:虽然
PointF*
可以传递其自身的偏移信息,它不能传递长度-因此您需要始终传递
PointF*
length
。当您这样做时,您可能已经使用了
ArraySegment
,它的附带好处是不需要任何
不安全的
代码。当然,根据场景的不同,将大型阵列视为非托管内存可能(在某些场景中)仍然很诱人。

假设您确信可以避免OutOfMemoryException,并且将其全部存储在内存中的方法不是真正的问题(如果内存可用,GC非常擅长阻止这种情况发生)

  • 这是你的第一个问题。我不确定CLR。
    • 关键编辑-在64位系统上更改此选项-在推出您自己的解决方案之前尝试此选项
  • 第二,你说的是“有些是保留的,有些是保留的”。i、 e.您希望在使用“子数组”后能够重新分配数组的元素
  • 第三,我假设
    PointF[]gianticlist=newpointf[100]更像是
    PointF[]gianticlist=newpointf[1000000]

也考虑使用,因为这允许您“要求”内存并检查异常,而不是用OutOfMeMyExeExchange崩溃。

编辑也许最重要的是,您现在正在进入一个权衡的领域。如果这样做,可能会开始失去循环开始时的循环数组(
for(inti=0;i
得到优化,
int length=5;for(int i=0;i
没有优化。如果您有高计算资源代码,那么这可能会伤害您。您还必须更加努力地工作,以便并行处理不同的子数组。创建子数组的副本,或子数组的部分,甚至子数组中的项,仍然需要分配更多的内存,这些内存将被GC分配

这可以通过包装数组并跟踪哪些节用于哪些子数组来实现。实际上,您所说的是分配一大块内存,然后重用其中的一部分,而无需让GC承担责任。您可以利用,但这会带来自身的潜在问题,如向所有调用者公开原始数组

这并不简单,但却是可能的。很可能不是每次删除子阵列时,您都希望通过移动其他子阵列来缩小间隙(或者在连续段用完时执行此操作),从而对主阵列进行碎片整理

下面的一个简单示例类似于(未经测试,如果您的计算机离开家而您的猫爆炸了,请不要怪我)伪代码。还有另外两种方法,我在最后提到

公共类数组集合{
List startIndexes=新列表();
列表长度=新列表();
常数int 1beeellion=100;
PointF[]GRANGINACLIST=新的PointF[1BEELLION];
公共阵列整理此[int childIndex]{
得到{
//使用此方法时,ArraySegment会公开原始数组,然后调用者可以使用该数组
//做坏事
返回新的ArraySegment(gignaclist,startIndexes[childIndex],length[childIndex]);
}}
//返回子数组的索引
公共整数AddChild(整数长度){
//TODO:需要考虑没有条目的列表
int startIndex=startIndexes.Last()+length.Last();
//TODO:检查startIndex+长度是否不大于0
//如果是的话
//查找大于请求长度的最小未使用块
//或者对未使用的数组部分进行碎片整理
//否则,将抛出内存
startIndexes.Add(startIndex);//需要插入碎片整理操作
length.Add(length);//碎片整理操作需要插入
return startIndexes.Count-1;//inserts将需要返回插入的索引
}      
公共阵列整理GetChildAsSegment(int childIndex){
//使用此方法时,ArraySegment会公开原始数组,然后调用者可以使用该数组
//做坏事
返回新的ArraySegment(gignaclist,startIndexes[childIndex],length[childIndex]);
}
public void SetChildValue(int-childIndex、int-elementIndex、Point
PointF[] giganticList = new PointF[100];
// I want the segment length to be 20 and starting e.g at position 50 
// within the gigantic list
var segment = new ArraySegment<PointF>(giganticList, 50, 20);