Çok sayıda dizeyi kullanan bir uygulamam var. Yani bazı bellek kullanımı problemim var. Bu durumda en iyi çözümlerden birinin bir DB kullanmak olduğunu biliyorum, ancak şimdilik bunu kullanamıyorum, bu yüzden başkaları için çözümler arıyorum.Dize VS Byte [], bellek kullanımı
C# dizesinde, Utf16'da depolanıyor, yani bellek kullanımının yarısını Utf8 ile karşılaştırıyorum (dizelerimin büyük kısmı için). Bu yüzden, utf8 dizesinin bayt dizisini kullanmaya karar verdim. Ama benim için sürprizim bu çözüm benim uygulamada basit dizelerden iki kat daha fazla bellek alanı aldı.
Bazı basit testler yaptım, ancak uzmanların görüşlerini tam olarak bilmek istiyorum.
Testi 1: Sabit uzunluk dizeleri tahsis
var stringArray = new string[10000];
var byteArray = new byte[10000][];
var Sb = new StringBuilder();
var utf8 = Encoding.UTF8;
var stringGen = new Random(561651);
for (int i = 0; i < 10000; i++) {
for (int j = 0; j < 10000; j++) {
Sb.Append((stringGen.Next(90)+32).ToString());
}
stringArray[i] = Sb.ToString();
byteArray[i] = utf8.GetBytes(Sb.ToString());
Sb.Clear();
}
GC.Collect();
GC.WaitForFullGCComplete(5000);
Bellek Kullanımı
00007ffac200a510 1 80032 System.Byte[][]
00007ffac1fd02b8 56 152400 System.Object[]
000000bf7655fcf0 303 3933750 Free
00007ffac1fd5738 10004 224695091 System.Byte[]
00007ffac1fcfc40 10476 449178396 System.String
Gördüğümüz gibi, diziler iki kez daha az bellek alanı, burada gerçek sürpriz almak bayt.
Testi 2: (gerçekçi uzunluğunda) Rastgele boyut dize tahsisi
var stringArray = new string[10000];
var byteArray = new byte[10000][];
var Sb = new StringBuilder();
var utf8 = Encoding.UTF8;
var lengthGen = new Random(2138784);
for (int i = 0; i < 10000; i++) {
for (int j = 0; j < lengthGen.Next(100); j++) {
Sb.Append(i.ToString());
stringArray[i] = Sb.ToString();
byteArray[i] = utf8.GetBytes(Sb.ToString());
}
Sb.Clear();
}
GC.Collect();
GC.WaitForFullGCComplete(5000);
Bellek Kullanımı
00007ffac200a510 1 80032 System.Byte[][]
000000be2aa8fd40 12 82784 Free
00007ffac1fd02b8 56 152400 System.Object[]
00007ffac1fd5738 9896 682260 System.Byte[]
00007ffac1fcfc40 10368 1155110 System.String
Dize iki saatten daha bayt dizisinin hafıza alanını biraz daha az yer alır . Daha kısa dize ile dizeler için daha büyük bir yük bekleniyordu. Ama öyle görünüyor ki, tam tersi?
Testi 3: Uygulamam
var stringArray = new string[10000];
var byteArray = new byte[10000][];
var Sb = new StringBuilder();
var utf8 = Encoding.UTF8;
var lengthGen = new Random();
for (int i=0; i < 10000; i++) {
if (i%2 == 0) {
for (int j = 0; j < lengthGen.Next(100000); j++) {
Sb.Append(i.ToString());
stringArray[i] = Sb.ToString();
byteArray[i] = utf8.GetBytes(Sb.ToString());
Sb.Clear();
}
} else {
stringArray[i] = Sb.ToString();
byteArray[i] = utf8.GetBytes(Sb.ToString());
Sb.Clear();
}
}
GC.Collect();
GC.WaitForFullGCComplete(5000);
Bellek Kullanımı Burada
00007ffac200a510 1 80032 System.Byte[][]
00007ffac1fd02b8 56 152400 System.Object[]
00007ffac1fcfc40 5476 198364 System.String
00007ffac1fd5738 10004 270075 System.Byte[]
dizeleri bayt çok daha az bellek alanını almaya gelen dize modeli. Bu şaşırtıcı olabilir, ama boş dize sadece bir kez atıfta bulunulduğunu farz ettim. Bu mu? Ama bu büyük farkın açıklanıp açıklanamayacağını bilmiyorum. Başka bir sebep mi var? En iyi çözüm nedir?
'kullanmak string.IsNullOrEmpty (stringArray [i])' değildir Neden ? –
@MarkJansen Bu sadece bir örnek: 'stringArray [i]' in 'else 'dalında' if (i% 2 == 0)' koşulunda boş olduğundan emin olduğumu biliyorum, böylece karşılaştırmayı atlayabilirdim 'string.Empty' tamamen. – dasblinkenlight
İlginç, gerçekten boş bir bayt referans kullanın bellek kullanımını çok artırın. Gönderiimde, 64 bitlik ve birim bayt olduğunu söylemeyi unuttum. Her neyse bu açıklama fikrinizi değiştirmez, bir işaretçi için 34 byte olsa bile (her dizenin 26 baytlık ek yükü ile daha fazla) bulsam bile. System.Byte [] [] ile 10K işaretçisinin boyutunu (80032 KB, yani kullanışlı bellek boyutunun% 25'i) kaybettim. Bu kadar dolaylı kullanımdan kaçınmanın bir yolu var mı? Belki de bayt dizisi ile değil. – Edeen