Neden yapılar benim dizi çok fazla bellek kadar sürebilir?
Soru:Nasıl Mikro Çerçeve yapılar bir dizi için bellek ayrılamadı?
Çoğaltmak için kod BitBucket repository.
İçerik ve Ayrıntı
Kuyruğa Ekle gecikmeler için sabit boyutlu bir dizi kullanarak bir USB Klavye vuruşlarını işleme yapıyorum. Anahtar ve göstermek için struct
olaylar ve gecikme kullanıyorum.
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.
}
QueuedEvent
işgal ederdi benim sanırdım4hafızasına bayt, ama çöp toplayıcı (özellikle VALUETYPE
SZARRAY
tip) hata ayıklama çıktısına bakarak dayanarak aslında kaplıyor84bayt her! Bu overkill gibi saldırıyor! (Ve gerçekten anlıyorum çünkü 84 bayt her bir görünüyor, bir eğer 512 ben ayırma işlemi OutOfMemoryException
. RAM ~20kB mevcut, yani 512 de ayırmak gerekir kolay).
Soru (tekrar):Nasıl Mikro Çerçeve 4 uygun olabilecek bir yapı için 84 bayt ayırmaya yönetir?
Çöp Toplayıcı Rakamlar
Burada farklı bir tablo QueuedEvent
I 0 ı ne zaman tahsis miktarda çıkarma sonra () dizileri boy:
-------- ----------- ----------- --------- ------------ -------
| 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 |
-------- ----------- ----------- --------- ------------ -------
SZARRAY
sayı dayalı, QueuedEvent
benim alanları Int32 sınırlarını hizalı ediliyor, böylece alarak tahmin ediyorum12bayt. Ama fazladan 72 bayt nereden geldiği hakkında hiçbir fikrim yok.
Düzenleme:Debug.GC(true)
arama ve hata ayıklayıcı benim çıktı aldığım dökümü gözlemleyerek bu sayılar alıyorum. Her sayının anlamı tam olarak tanımlayan bir referans bulamadım.
Sadece yapı güzel sarma kaybedeceğim anlamına gelir int[]
ama ve herhangi bir tür bir güvenlik tahsis edebileceğimi fark ettim. Ve gerçekten bir yapı gerçek maliyeti mikro çerçevede ne olduğunu bilmek istiyorum.
TinyTimeSpan
benim dışında TimeSpan
düzenli gibi Int16
bir milisaniye yerine bir Int64 100ns kene temsil eden bir sayıyı temsil etmek için kullanıyor.
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; } }
}
FEZ Domino gibi bir donanım kullanıyorum. Donanım özeldir bu tamamen mümkün. Ayrıca, Mikro Çerçeve 4.1.
Edit - Daha Fazla Test Ve Yorum Cevap
Araştırdım bir sürü testler (öykünücüsü bu kez gerçek bir donanım, ama sayıları için QueuedEvent
aynı, bu yüzden ben varsayarsak benim donanım olurdu aynı diğer testler için).
Çoğaltmak için kod BitBucket repository.
Aşağıdaki integral türleri ve yapılar VALUETYPE
yükü: herhangi bir çekmezler
- Byte (1 byte)
- Açıklayan 32 bitlik tamsayı (4 bayt)
- Int16 (2 bayt)
- Int64 (8 bayt)
- Double (8 Byte)
- Zaman aralığı (12 bayt dahili üye bir Int64 gibi garip,)
- DateTime (12 bayt - tuhaf)
Ancak, Guid
yapar: 36 bayt kullanarak. her
Boş statik üye VALUETYPE
, 72 bayt (12 bayt bir dizi aynı yapı daha az) kullanarak ayırır.
static
bir üyesi olarak dizi ayrılırken bir şey değiştirmez.
Hata Ayıklama veya Sürüm modlarında çalışan hiç fark etmez. Bir hata ayıklayıcı rağmen bağlı olmadan GC hata ayıklama bilgileri almak için nasıl bilmiyorum. Ama Mikro Çerçeve bağlantısız bir hata ayıklayıcı zaten ne olurdu bilmiyorum yorumlanır.
Mikro Çerçeve unsafe
kod desteklemiyor. Ne 27* Explicit
*(, değil mi ama FieldOffset
özniteliği yok hayır teknik olarak) desteklemiyor . * Auto
*30 ve Sequential
hiçbir şey değiştirmez.
Burada are birkaç daha fazla yapılar ve ölçülen bellek ayırma:
// 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
{
}
Özel bir yapı kullanıyorum her zaman gibi görünüyor, Tepegöz gibi birşey tabi. Ve bu yapı içinde ben dahil ne olursa olsun, her zaman SZARRAY
12 bayt gerektirir. Yani bu çalıştı:
// 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;
}
Küçük Değişiklik
Kendi cevabımı yazdıktan sonra, her zaman her öğe için SZARRAY
12 byte bir yük olduğunu fark ettim. object[]
bir test ettim. Başvuru türleri Mikro Çerçevesinde 12 bayt her tüketirler.
Boş bir yapı public struct Empty { }
24 bayt her tüketir.
CEVAP
Benim testlere bağlı olarak, Mikro Çerçevesinde ValueTypes
masaüstü CLR üzerinde alıştığımız gibi gerçek değeri olan türler olmadığını tahmin ediyorum. En azından kutulu ediliyor. Ve yönlendirme başka bir düzeyi de dahil olabilir. Bu maliyetler bir () gömülü bir platform için oldukça büyük bir bellek yükü meydana gelmiştir.
int[]
FixedSizedQueue
dönüştürme olacağım
Aslında UInt32[]
kullandım ve biraz uzatma yöntemleri biraz dayak sararak ekledi.
Etrafında source code biraz bakındım ama işe yarar bir şey (ve ben gerçekten de Ne aramak için bilmiyorum) bulamadı.
Neden TextBox ekleme yapar.Bir döngü s...
Neden&; dizi yineleme için... "* o kad...
Neden git benim depo bu kadar büyük?...
Neden CUDA iğnelenmiş bellek o kadar h...
Neden ilk eleman benim Raylar her zama...