lig*_*gos 59 .net c# memory-management .net-micro-framework out-of-memory
问题: Micro Framework如何为结构数组分配内存?
BitBucket存储库,包含要复制的代码.
我正在使用固定大小的数组来排队,以便在处理来自USB键盘的击键时插入延迟.我用a struct代表键上下事件和延迟.
public struct QueuedEvent
{
public readonly EventType Type; // Byte
public readonly byte KeyPressed;
public readonly TinyTimeSpan Delay; // Int16
public readonly static QueuedEvent Empty = new QueuedEvent();
}
public enum EventType : byte
{
None = 0,
Delay = 1,
KeyDown = 2,
KeyUp = 3,
KeyPress = 4,
}
public class FixedSizeQueue
{
private readonly QueuedEvent[] _Array;
private int _Head = 0;
private int _Tail = 0;
public FixedSizeQueue(int size)
{
_Array = new QueuedEvent[size];
}
// Enqueue and Dequeue methods follow.
}
Run Code Online (Sandbox Code Playgroud)
我原本以为我QueuedEvent会在内存中占用4个字节,但是,基于查看垃圾收集器的调试输出(特别是VALUETYPE和SZARRAY类型),它实际上每个占用84个字节!这让我觉得有点矫枉过正!(它实际上看起来每个都是84个字节,因为OutOfMemoryException如果我分配了512 个字节,我会得到一个.我有~20kB的RAM可用,所以我应该能够轻松地分配512个).
问题(再次): Micro Framework如何为一个可以容纳4的结构分配84个字节?
这是一个不同大小的数组表QueuedEvent(在我分配0后减去数量):
+--------+-----------+-----------+---------+------------+-------+
| Number | VALUETYPE | B/Q'dEvnt | SZARRAY | B/Q'edEvnt | Total |
| 16 | 1152 | 72 | 192 | 12 | 84 |
| 32 | 2304 | 72 | 384 | 12 | 84 |
| 64 | 4608 | 72 | 768 | 12 | 84 |
| 128 | 9216 | 72 | 1536 | 12 | 84 |
+--------+-----------+-----------+---------+------------+-------+
Run Code Online (Sandbox Code Playgroud)
基于SZARRAY数字,我猜我的QueuedEvent字段与Int32边界对齐,因此占用12个字节.但我不知道额外的72字节来自哪里.
编辑:我通过调用Debug.GC(true)并观察调试器输出中的转储来获取这些数字.我还没有找到一个参考,它确切地标出了每个数字的含义.
我意识到我可以简单地分配一个int[],但这意味着我失去了良好的封装和结构的任何类型安全性.而且我真的想知道结构体在微框架中的真正成本是什么.
我TinyTimeSpan很像常规,TimeSpan除了使用一个Int16代表几毫秒而不是一个代表100ns刻度的Int64.
public struct TinyTimeSpan
{
public static readonly TinyTimeSpan Zero = new TinyTimeSpan(0);
private short _Milliseconds;
public TinyTimeSpan(short milliseconds)
{
_Milliseconds = milliseconds;
}
public TinyTimeSpan(TimeSpan ts)
{
_Milliseconds = (short)(ts.Ticks / TimeSpan.TicksPerMillisecond);
}
public int Milliseconds { get { return _Milliseconds; } }
public int Seconds { get { return _Milliseconds * 1000; } }
}
Run Code Online (Sandbox Code Playgroud)
我正在使用FEZ Domino作为硬件.这完全有可能是硬件特定的.另外,Micro Framework 4.1.
我跑了更多的测试(这次在模拟器中,而不是在真正的硬件上,但数字QueuedEvent是相同的,所以我假设我的硬件与其他测试相同).
BitBucket存储库,包含要复制的代码.
以下整数类型和结构不会产生任何开销,因为VALUETYPE:
但是,Guid确实:每个使用36个字节.
空静态成员VALUETYPE使用72个字节进行分配(比数组中的相同结构少12个字节).
将数组分配为static成员不会改变任何内容.
在调试或发布模式下运行没有任何区别.我不知道如何在没有连接调试器的情况下获取GC调试信息.但是Micro Framework被解释了,所以我不知道非附加调试器会有什么影响.
Micro Framework不支持unsafe代码.它也不支持StructLayout Explicit(嗯,技术上它支持,但没有FieldOffset属性).StructLayout Auto并Sequential没有任何区别.
以下是几个结构及其测量的内存分配:
// Uses 12 bytes in SZARRAY and 24 in VALUETYPE, total = 36 each
public struct JustAnInt32
{
public readonly Int32 Value;
}
// Uses 12 bytes in SZARRAY and 48 in VALUETYPE, total = 60 each
// Same as original QueuedEvent but only uses integral types.
public struct QueuedEventSimple
{
public readonly byte Type;
public readonly byte KeyPressed;
public readonly short DelayMilliseconds;
// Replacing the short with TimeSpan does not change memory usage.
}
// Uses 12 bytes in SZARRAY and 12 in VALUETYPE, total = 24 each
// I have to admit 24 bytes is a bit much for an empty struct!!
public struct Empty
{
}
Run Code Online (Sandbox Code Playgroud)
似乎每次我使用自定义结构时,都会产生某种开销.无论我在结构中包含什么,它总是需要12个字节SZARRAY.所以我尝试了这个:
// Uses 12 bytes in SZARRAY and 36 in VALUETYPE, total = 48 each
public struct DifferentEntity
{
public readonly Double D;
public readonly TimeSpan T;
}
// Uses 12 bytes in SZARRAY and 108 in VALUETYPE, total = 120 each
public struct MultipleEntities
{
public readonly DifferentEntity E1;
public readonly DifferentEntity E2;
}
// Uses 12 bytes in SZARRAY and 60 in VALUETYPE, total = 72 each
// This is equivalent to MultipleEntities, but has quite different memory usage.
public struct TwoDoublesAndTimeSpans
{
public readonly double D1;
public readonly TimeSpan T1;
public readonly double D2;
public readonly TimeSpan T2;
}
Run Code Online (Sandbox Code Playgroud)
在发布我自己的答案之后,我意识到SZARRAY每个项目总是有12字节的开销.所以我测试了一个object[].Micro Framework中的引用类型各占12个字节.
空结构public struct Empty { }每个消耗24个字节.