【发布时间】:2015-10-26 16:28:40
【问题描述】:
我有一个使用大量字符串的应用程序。所以我有一些内存使用问题。 我知道在这种情况下最好的解决方案之一是使用数据库,但我暂时不能使用它,所以我正在寻找其他解决方案。
在 C# 中,字符串存储在 Utf16 中,这意味着与 Utf8 相比,我损失了一半的内存使用量(对于我的字符串的主要部分)。 所以我决定使用 utf8 字符串的字节数组。但令我惊讶的是,这个解决方案比我的应用程序中的简单字符串占用的内存空间多两倍。
所以我做了一些简单的测试,但我想知道专家的意见以确保。
测试 1:固定长度字符串分配
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);
内存使用
00007ffac200a510 1 80032 System.Byte[][]
00007ffac1fd02b8 56 152400 System.Object[]
000000bf7655fcf0 303 3933750 Free
00007ffac1fd5738 10004 224695091 System.Byte[]
00007ffac1fcfc40 10476 449178396 System.String
正如我们所见,字节数组占用的内存空间减少了两倍,这并不奇怪。
测试 2:随机大小的字符串分配(具有实际长度)
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);
内存使用
00007ffac200a510 1 80032 System.Byte[][]
000000be2aa8fd40 12 82784 Free
00007ffac1fd02b8 56 152400 System.Object[]
00007ffac1fd5738 9896 682260 System.Byte[]
00007ffac1fcfc40 10368 1155110 System.String
字符串占用的空间比字节数组内存空间的两倍少一点。对于较短的字符串,我期望字符串的开销更大。 但似乎恰恰相反,为什么呢?
测试3:我的应用对应的字符串模型
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);
内存使用
00007ffac200a510 1 80032 System.Byte[][]
00007ffac1fd02b8 56 152400 System.Object[]
00007ffac1fcfc40 5476 198364 System.String
00007ffac1fd5738 10004 270075 System.Byte[]
这里字符串占用的内存空间比字节少得多。这可能令人惊讶,但我认为空字符串只被引用一次。是吗?但我不知道这是否能解释所有巨大的差异。难道还有别的原因吗?最好的解决方案是什么?
【问题讨论】: