我的任务是在我的应用程序中消除对大对象堆的所有(或尽可能多的)分配。最大的违规者之一是我们计算大字符串的 MD5 哈希的代码。
public static string MD5Hash(this string s)
{
using (MD5CryptoServiceProvider csp = new MD5CryptoServiceProvider())
{
byte[] bytesToHash = Encoding.UTF8.GetBytes(s);
byte[] hashBytes = csp.ComputeHash(bytesToHash);
return Convert.ToBase64String(hashBytes);
}
}
为了示例的缘故,字符串本身可能已经在 LOH 中。我们的目标是防止对堆进行更多分配。
此外,当前的实现假设 UTF8 编码(一个很大的假设),但真正的目标是从字符串生成一个 byte[]。
MD5CryptoServiceProvider 可以将 Stream 作为输入,因此我们可以创建一个方法:
public static string MD5Hash(this Stream stream)
{
using (MD5CryptoServiceProvider csp = new MD5CryptoServiceProvider())
{
return Convert.ToBase64String(csp.ComputeHash(stream));
}
}
这是有希望的,因为我们不需要 byte[] 来让 ComputeHash 工作。我们需要一个流对象,它将在 ComputeHash 请求字节时从字符串中读取字节。
这个颇具争议的问题提供了一种从字符串创建字节数组的方法,而不管编码如何。但是,我们要避免创建大字节数组。
这个问题提供了一种通过将字符串读入 MemoryStream 来从字符串创建流的方法,但在内部也只是分配了一个大的 byte[] 数组。
两者都不是真正的伎俩。
那么如何避免分配大字节[]呢?是否有一个 Stream 类会在读取字节时从另一个流(或读取器)读取?