SORU
16 EYLÜL 2012, Pazar


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
16 EYLÜL 2012, Pazar


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.

Benim 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ı.

Bunu Paylaş:
  • Google+
  • E-Posta
Etiketler:

YORUMLAR

SPONSOR VİDEO

Rastgele Yazarlar

  • chrmoe

    chrmoe

    7 Kasım 2006
  • GoldgenieOfficial

    GoldgenieOff

    23 Temmuz 2009
  • TheDamnWreckless

    TheDamnWreck

    12 Temmuz 2010