我有一个应用程序使用了大量字符串,因此我遇到了一些内存使用问题。我知道在这种情况下最好的解决方案之一是使用数据库,但目前我无法使用它,所以我正在寻找其他解决方案。
在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[]
使用“Here strings”比使用字节占用更少的内存空间。这可能令人惊讶,但我认为空字符串只被引用一次。是吗?但我不知道这是否能解释所有巨大的差异。还有其他原因吗?最好的解决方案是什么?
String.IsNullOrEmpty(stringArray[i])
? - Mark Jansenif (i%2 == 0)
条件的else
分支中,stringArray[i]
是空的,所以我本来可以完全跳过与string.Empty
的比较。 - Sergey Kalinichenko