gpt4 book ai didi

c# - String VS Byte[],内存使用情况

转载 作者:IT王子 更新时间:2023-10-28 23:31:51 28 4
gpt4 key购买 nike

我有一个使用大量字符串的应用程序。所以我有一些内存使用问题。我知道在这种情况下最好的解决方案之一是使用数据库,但我暂时不能使用它,所以我正在寻找其他解决方案。

在 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[]

这里字符串占用的内存空间比字节少得多。这可能令人惊讶,但我认为空字符串只被引用一次。是吗?但我不知道这是否能解释所有巨大的差异。难道还有别的原因吗?最好的解决方案是什么?

最佳答案

This can be surprising, but I supposed that empty string are referenced only once.

是的,一个空的 StringBuilder 会返回 string.Empty 作为其结果。下面的代码片段打印出 True:

var sb = new StringBuilder();
Console.WriteLine(object.ReferenceEquals(sb.ToString(), string.Empty));

But I don't know if this can explain all that huge difference.

是的,这完美地解释了它。您节省了 5,000 个 string 对象。字节差大约是 270,000-(198,000/2),所以大约是 170 kBytes。除以 5 得到每个对象 34 个字节,这大约是 32 位系统上指针的大小。

What is the best solution?

做同样的事情:让自己成为一个 private static readonly 空数组,每次从 sb.ToString( ):

private static readonly EmptyBytes = new byte[0];
...
else
{
stringArray[i] = Sb.ToString();
if (stringArray[i] == string.Empty) {
byteArray[i] = EmptyBytes;
} else {
byteArray[i] = utf8.GetBytes(Sb.ToString());
}
Sb.Clear();
}

关于c# - String VS Byte[],内存使用情况,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31806375/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com