错误:ZLibStreamHandle 类型的 SafeHandle 或 CriticalHandle 未能正确释放
Posted
技术标签:
【中文标题】错误:ZLibStreamHandle 类型的 SafeHandle 或 CriticalHandle 未能正确释放【英文标题】:error: a SafeHandle or CriticalHandle of type ZLibStreamHandle failed to properly release 【发布时间】:2016-04-18 20:29:14 【问题描述】:我在流方面工作不多,所以我认为我这里的某个地方存在编码错误。
public static SqlBytes Compress(SqlBytes input)
byte[] data = (byte[])input.Value;
using (MemoryStream memstream = new MemoryStream(data))
using (GZipStream zipped = new GZipStream(memstream, CompressionMode.Compress))
using (MemoryStream output = new MemoryStream())
zipped.CopyTo(output);
return new SqlBytes(output.ToArray());
这是 SQL Server 2012 CLR 中的错误:
Msg 10323, Level 16, State 49, Line 1
Invalid user code has been identified by .Net Framework Managed Debug Assistant 'releaseHandleFailed':
A SafeHandle or CriticalHandle of type 'ZLibStreamHandle' failed to properly release the handle with value 0x0000000000000000. This usually indicates that the handle was released incorrectly via another means (such as extracting the handle using DangerousGetHandle and closing it directly or building another SafeHandle around it.)
at System.Runtime.InteropServices.SafeHandle.InternalDispose()
at System.IO.Compression.DeflaterZLib.Dispose(Boolean disposing)
at System.IO.Compression.DeflateStream.Dispose(Boolean disposing)
at System.IO.Stream.Close()
at System.IO.Compression.GZipStream.Dispose(Boolean disposing)
at System.IO.Stream.Close()
at UserDefinedFunctions.Compress(SqlBytes input)
at SQLCLR_Eval(IntPtr , IntPtr , IntPtr )
【问题讨论】:
【参考方案1】:由 .Net Framework Managed Debug Assistant 识别
这不是例外,只是来自 MDA(托管调试助手)的通知。集成在 CLR 中的少量代码用于检查常见的运行时错误。没有硬异常的帮助就很难诊断的那种。只有在使用调试器时才会收到 MDA 通知。而且只有在启用 MDA 的情况下,大多数都没有。
'releaseHandleFailed'
说出来的 MDA 是一个检查 SafeHandle 是否被正确使用的 MDA。在这种特定情况下,它是ZLibStreamHandle class。实际的解压/压缩由 Zlib 完成,这是一个用本机代码编写的开源库。 SafeHandles 通常用于管理非托管资源,它们确保使用关键终结器释放此类资源。
releaseHandleFailed
MDA 值得注意的是,它通常会关闭。它应该由编写 SafeHandle 类的程序员打开,例如编写 ZLibStreamHandle 的 Microsoft 程序员。因此,虽然此通知背后的错误可能很常见,但几乎没有人看到它。从未被诊断出的错误永远不会得到修复。
未能正确释放值为 0x0000000000000000 的句柄
这告诉您 MDA 警告完全是良性的。没有实际的非托管资源被不当释放,也不会出错,底层句柄为空。当您按 F5 继续运行时,您的程序将继续愉快地运行。与验证 4.5 框架中更改的任何单元测试一样,MDA 在单元测试中不活跃。
尽管如此,确实出了点问题,不应该为空句柄创建 ZLibStreamHandle 对象。我看不出有什么明显的方法是如何在课堂上搞砸的。当然,最初的 Microsoft 开发人员也没有看到它 :) 这个 MDA 通常由终结器触发。这里不是这种情况,using 语句(又名 Dispose() 调用)触发了它。这很不寻常,我怀疑在你得到一个异常之前你得到了这个 MDA,告诉你在本机代码中出现了一些问题。发生是因为 using 语句生成了一个 finally 块,该块在报告异常之前执行。如果那是准确的,那么按 F5 应该会发现真正的问题。
对于框架代码中的错误,您无能为力。除了报告它以便 Microsoft 可以修复它,使用 connect.microsoft.com 告诉他们。
然后关闭 MDA,这样您就可以像其他人一样愉快地忽略它。调试 > 异常 > 托管调试助手 > 取消选中 ReleaseHandleFailed。如果您都勾选了它们,这是意外启用 MDA 的最典型方式,然后重置父级的复选框。
【讨论】:
我自己也遇到了这个问题,值得注意的是我在压缩 0 字节大小的文件时遇到了异常。当我在文件中添加一些文本行时,我不再遇到异常。我正在使用 System.IO.Compression.ZipFile.CreateFromDirectory 并且该文件位于我正在压缩的目录中。因此,在压缩 0 字节的内容时,您似乎会收到此错误。【参考方案2】:就我而言,只是数据库在其数据被压缩的列中有空字符串。当您仅使用 SQL 2012 压缩/解压缩空字符串时,就会出现问题。在 SQL 2008/2008R2 中看不到它。希望这会有所帮助。
【讨论】:
以上是关于错误:ZLibStreamHandle 类型的 SafeHandle 或 CriticalHandle 未能正确释放的主要内容,如果未能解决你的问题,请参考以下文章
s-s-rs-report:如何修复错误过程需要“ntext/nchar/nvarchar”类型的参数“@parameters”
在其他容器中使用 boost::container::static_vector 时,gcc 编译错误“将‘const s’绑定到‘s&’类型的引用丢弃限定符”
Spring boot 4 控制器错误:CrudRepository<Fournisseur,Long> 类型中的方法 save(S) 不适用于参数 (Fournisseur)