Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/320.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何避免在计算大字符串哈希时分配大字节[]_C#_Stream_Large Object Heap - Fatal编程技术网

C# 如何避免在计算大字符串哈希时分配大字节[]

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);

我的任务是在我的应用程序中尽可能地消除所有(或尽可能多的)分配给大型对象堆。最大的问题之一是我们计算大字符串的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可以将流作为输入,因此我们可以创建一个方法:

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。