C# 如何避免在计算大字符串哈希时分配大字节[]
我的任务是在我的应用程序中尽可能地消除所有(或尽可能多的)分配给大型对象堆。最大的问题之一是我们计算大字符串的MD5散列的代码C# 如何避免在计算大字符串哈希时分配大字节[],c#,stream,large-object-heap,C#,Stream,Large Object Heap,我的任务是在我的应用程序中尽可能地消除所有(或尽可能多的)分配给大型对象堆。最大的问题之一是我们计算大字符串的MD5散列的代码 public static string MD5Hash(this string s) { using (MD5CryptoServiceProvider csp = new MD5CryptoServiceProvider()) { byte[] bytesToHash = Encoding.UTF8.GetBytes(s);
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可以将流作为输入,因此我们可以创建一个方法:
public static string MD5Hash(this Stream stream)
{
using (MD5CryptoServiceProvider csp = new MD5CryptoServiceProvider())
{
return Convert.ToBase64String(csp.ComputeHash(stream));
}
}
这是有希望的,因为我们不需要字节[]来让ComputeHash工作。我们需要一个stream对象,该对象将在ComputeHash请求字节时从字符串中读取字节
提供从字符串创建字节数组的方法,而不考虑编码。但是,我们希望避免创建大字节数组
提供一种通过将字符串读入MemoryStream从字符串创建流的方法,但在内部,该方法也只是分配一个大字节[]数组
两者都没有真正起作用
那么,如何避免分配大字节[]?是否有一个流类会在读取字节时从另一个流(或读取器)中读取数据?您可以实现自己的流,该流由字符串支持 请注意,基本上,您只需要实现
读取
和写入
,相应地使用文档(但只需在写入
上抛出NotSupportedException
,因为您不应该写入此流):
实现流的派生类时,必须提供读写方法的实现。异步方法ReadAsync、WriteAsync和CopyToAsync在其实现中使用同步方法Read和Write
您可能还想实现ReadByte
:
ReadByte和WriteByte的默认实现创建一个新的单元素字节数组,然后调用读写实现
来源:如果您不关心编码,那么您可以做一件事来防止进一步的缓冲区分配,那就是使用一些不安全的代码。也就是说,获取字符串的原始字节,将
UnmanagedMemoryStream
的一个实例包装在其周围,并将其提供给MD5加密计算
比如说:
public static string MD5Hash(this string s)
{
using (MD5CryptoServiceProvider csp = new MD5CryptoServiceProvider())
{
unsafe
{
fixed (char* input = s)
{
using (var stream = new UnmanagedMemoryStream((byte*)input, sizeof(char) * s.Length))
return Convert.ToBase64String(csp.ComputeHash(stream));
}
}
}
}
这个MD5计算有多关键?如果时间不太紧迫,您可以将字符串写入(临时)文件,创建文件流并将其提供给MD5CryptoServiceProvider。