我正在从事一项物理模拟项目,性能非常重要,而我认为我的内存管理是瓶颈之一。目前,我有包含固定数量刚体、粒子和力的缓冲区对象。在模拟开始之前,所有的物理实体都在其缓冲区内进行初始化。当需要一个实体时,选择第一个非活动的实体,否则选择最旧的实体;当它不再需要时,将其移动到末尾,这样活动的实体就都排在前面。
这是我正在使用的数据结构。
public sealed class Buffer<TValue> : IEnumerable<BufferElement<TValue>> where TValue : new()
{
public Buffer(int capacity)
{
Count = 0;
Capacity = capacity;
Elements = new BufferElement<TValue>[capacity];
for (var index = 0; index < Elements.Length; index++)
{
Elements[index] = new BufferElement<TValue>();
}
}
public int Count { get; private set; }
public int Capacity { get; private set; }
private int ActiveCount { get; set; }
private BufferElement<TValue>[] Elements { get; }
public BufferElement<TValue> Activate()
{
if (Count == ActiveCount) Count = 0;
var bufferElement = Elements[Count++];
if (!bufferElement.Active)
{
bufferElement.Active = true;
ActiveCount++;
}
return bufferElement;
}
public void Deactivate(BufferElement element)
{
if (!element.Active) return;
element.Active = false;
var lhs = element.Index;
var rhs = --ActiveCount;
Elements[lhs] = Elements[rhs];
Elements[rhs] = element;
Elements[lhs].Index = lhs;
Elements[rhs].Index = rhs;
}
}
阅读了.NET Core处理数组的相关内容后,有两个问题可能会引起注意。第一个是每次访问数组中的元素时,都会执行安全检查,而第二个则是GC可能会将数组复制到新的内存地址。
如果可能的话,我希望所有包含物理实体的缓冲区都不进行任何安全检查,并且在连续的内存中固定。我相信这应该是可能的,因为每个缓冲区的大小都是固定的,元素的大小(刚体、粒子、力)也是固定的。
在C#中似乎有很多管理内存的方法,我很难确定在这种情况下哪种方法对我来说是正确的。
现在,问题分为三个部分:
1.是否可以做到? 2.如果可以,最好的内存管理方法是什么? 3.适当的实现应该是什么样子?
BufferElement
,我假设它是一个类,在这种情况下,数组将包含指针,而不是元素本身。我不清楚结构体是否会直接放入数组中,但如果是这样,它很可能会受到直接复制优化的类似限制。顺序布局仅在您对顺序元素执行足够数量(成比例)的工作时才有用-如果元素直接放入数组中,则这更容易实现。 - Clockwork-MuseBufferElement
确实是一个类,所以你是正确的,数组将是一个包含指针的连续内存块。由于物理实体不断被迭代,使它们在内存中顺序排列肯定会减少缓存未命中。你知道如何确保数组的内容也是连续的吗? - Jedi_Maseter_SamMarshal
不会分配连续的内存吗? - Jedi_Maseter_Sam