在x86上处理非常大的列表
本文关键字:列表 非常 处理 x86 | 更新日期: 2023-09-27 18:03:30
我需要处理大的浮点数列表,但是我在x86系统上遇到了内存限制。我不知道最终长度,所以我需要使用可扩展类型。在x64系统上,我可以使用<gcAllowVeryLargeObjects>
。
我当前的数据类型:
List<RawData> param1 = new List<RawData>();
List<RawData> param2 = new List<RawData>();
List<RawData> param3 = new List<RawData>();
public class RawData
{
public string name;
public List<float> data;
}
paramN列表的长度很低(目前为50或更低),但数据可以是10m+。当长度为50时,我在1m数据点以上达到内存限制(OutOfMemoryException
),当长度为25时,我在2m数据点以上达到内存限制。(如果我的计算是正确的,那就是200MB,加上名称的大小,再加上开销)。我可以用什么来增加这个极限?
编辑:我尝试使用List<List<float>>
的最大内部列表大小为1 <<17(131072),这增加了一些限制,但仍然没有达到我想要的程度。
Edit2:我尝试将列表中的块大小减少到8192,并且我在~2.3m元素处获得OOM,任务管理器为该进程读取~1.4GB。看起来我需要减少数据源和存储之间的内存使用,或者更频繁地触发GC -我能够在一台具有4GB RAM的pc上的x64进程中收集10m个数据点,IIRC进程从未超过3GB
Edit3:我将代码压缩到处理数据的部分。http://pastebin.com/maYckk84
Edit4:我在DotMemory中看了一下,发现我的数据结构确实占用了1GB的设置,我正在测试(50ch * 3 params * 2m事件= 300,000,000浮动元素)。我想我需要将其限制在x86上或者弄清楚如何在获取数据时以这种格式写入磁盘
首先,在x86系统上内存限制是2GB,而不是200MB。我想你的问题要棘手得多。有严重的LOH(大对象堆)碎片。
CLR对大小对象使用不同的堆。大于85000字节的对象是大对象。LOH是一个非常难以驾驭的东西,它不急于将未使用的内存返回给操作系统,并且它在碎片整理方面非常糟糕。
.Net List是ArrayList数据结构的实现,它将元素存储在固定大小的数组中;当数组被填充时,将创建大小加倍的新数组。随着数据量的不断增长,数组是LOH的"饥饿"场景。
因此,您必须使用定制的数据结构来满足您的需求。例如,块列表,每个块都足够小,不会进入LOH。这是一个小原型:
public class ChunkedList
{
private readonly List<float[]> _chunks = new List<float[]>();
private const int ChunkSize = 8000;
private int _count = 0;
public void Add(float item)
{
int chunk = _count / ChunkSize;
int ind = _count % ChunkSize;
if (ind == 0)
{
_chunks.Add(new float[ChunkSize]);
}
_chunks[chunk][ind] = item;
_count ++;
}
public float this[int index]
{
get
{
if(index <0 || index >= _count) throw new IndexOutOfRangeException();
int chunk = index / ChunkSize;
int ind = index % ChunkSize;
return _chunks[chunk][ind];
}
set
{
if(index <0 || index >= _count) throw new IndexOutOfRangeException();
int chunk = index / ChunkSize;
int ind = index % ChunkSize;
_chunks[chunk][ind] = value;
}
}
//other code you require
}
当ChunkSize
= 8000时,每个块将只占用32,000字节,因此它不会进入LOH。_chunks
只有在collection中有大约16000块时才会进入LOH,这意味着collection中有超过1.28亿个元素(约500 MB)。
UPD我已经对上面的示例执行了一些压力测试。操作系统为x64,解决方案平台为x86。ChunkSize = 20000
:
var list = new ChunkedList();
for (int i = 0; ; i++)
{
list.Add(0.1f);
}
OutOfMemoryException在~324,000,000个元素处引发
第二:public class RawData
{
public string Name;
public ChunkedList Data = new ChunkedList();
}
var list = new List<RawData>();
for (int i = 0;; i++)
{
var raw = new RawData { Name = "Test" + i };
for (int j = 0; j < 20 * 1000 * 1000; j++)
{
raw.Data.Add(0.1f);
}
list.Add(raw);
}
OutOfMemoryException在i= 17,j ~12,000,000处引发。成功创建17个RawData实例,每个实例2000万个数据点,总计约3.52亿个数据点。