C# CopyBlock 与 CopyBlockUnaligned 用例
C# CopyBlock vs CopyBlockUnaligned use cases
所以我正在学习加密哈希函数及其具体实现。由于 C# 是我的首选语言,我决定为 .NET Core 创建一个加密库。迟早我不得不使用一些不安全的代码来进行一些性能优化。
不出所料,我必须复制大量内存。到目前为止,我一直使用 Unsafe.CopyBlock()
来做这个。但是,似乎还有一个名为 Unsafe.CopyBlockUnaligned()
的函数。遗憾的是,documentation 并没有详细说明两者之间的区别(除了 Unsafe.CopyBlockUnaligned()
“不假定地址的体系结构相关对齐。”)
现在我想知道:选择 Unsafe.CopyBlock()
比 Unsafe.CopyBlockUnaligned()
有什么好处,或者它们有完全不同的用例吗?如果是这样,我应该什么时候使用哪个?如果有人可以解释两者之间的差异或向我指出一些文档,那就太好了。
在 Unsafe.CopyBlock()
和 Unsafe.CopyBlockUnalinged()
两次磕磕绊绊之后,我终于决定看一看 the source of System.Runtime.CompilerServices.Unsafe
。
比较CopyBlock()
的IL
.method public hidebysig static void CopyBlock(void* destination, void* source, uint32 byteCount) cil managed aggressiveinlining
{
.custom instance void System.Runtime.Versioning.NonVersionableAttribute::.ctor() = ( 01 00 00 00 )
.maxstack 3
ldarg.0
ldarg.1
ldarg.2
cpblk
ret
}
代码为CopyBlockUnaligned()
.method public hidebysig static void CopyBlockUnaligned(void* destination, void* source, uint32 byteCount) cil managed aggressiveinlining
{
.custom instance void System.Runtime.Versioning.NonVersionableAttribute::.ctor() = ( 01 00 00 00 )
.maxstack 3
ldarg.0
ldarg.1
ldarg.2
unaligned. 0x1
cpblk
ret
}
我们可以看到,唯一明显的区别是在 Unsafe.CopyBlockUnaligned()
实现中调用 cpblk
之前的 unaligned. 0x1
。由于我不太熟悉 IL,所以看一下 the documentation of System.Reflection.Emit.OpCodes.Unaligned
揭示了 unaligned
关键字的定义:
Indicates that an address currently atop the evaluation stack might not be aligned to the natural size of the immediately following ldind
, stind
, ldfld
, stfld
, ldobj
, stobj
, initblk
, or cpblk
instruction.
再往下说
Unaligned specifies that the address (an unmanaged pointer, native int
) on the stack might not be aligned to the natural size of the immediately following ldind
, stind
, ldfld
, stfld
, ldobj
, stobj
, initblk
, or cpblk
instruction. That is, for a Ldind_I4
instruction the alignment of the address may not be to a 4-byte boundary. For initblk
and cpblk
the default alignment is architecture dependent (4-byte on 32-bit CPUs, 8-byte on 64-bit CPUs).
因此可以肯定地说 Unsafe.CopyBlock()
只应在我们知道源地址和目标地址都对齐时才使用,目前 only inofficially includes addresses returned by Marshal.AllocHGLobal()
. However the upcoming .NET 6 (currently in preview) will bring us NativeMemory
我们自己控制内存对齐,这将允许我们使用Unsafe.CopyBlock()
更自由。因此,如果不确定对齐方式,建议只使用 Unsafe.CopyBlockUnaligned()
。
所以我正在学习加密哈希函数及其具体实现。由于 C# 是我的首选语言,我决定为 .NET Core 创建一个加密库。迟早我不得不使用一些不安全的代码来进行一些性能优化。
不出所料,我必须复制大量内存。到目前为止,我一直使用 Unsafe.CopyBlock()
来做这个。但是,似乎还有一个名为 Unsafe.CopyBlockUnaligned()
的函数。遗憾的是,documentation 并没有详细说明两者之间的区别(除了 Unsafe.CopyBlockUnaligned()
“不假定地址的体系结构相关对齐。”)
现在我想知道:选择 Unsafe.CopyBlock()
比 Unsafe.CopyBlockUnaligned()
有什么好处,或者它们有完全不同的用例吗?如果是这样,我应该什么时候使用哪个?如果有人可以解释两者之间的差异或向我指出一些文档,那就太好了。
在 Unsafe.CopyBlock()
和 Unsafe.CopyBlockUnalinged()
两次磕磕绊绊之后,我终于决定看一看 the source of System.Runtime.CompilerServices.Unsafe
。
比较CopyBlock()
.method public hidebysig static void CopyBlock(void* destination, void* source, uint32 byteCount) cil managed aggressiveinlining
{
.custom instance void System.Runtime.Versioning.NonVersionableAttribute::.ctor() = ( 01 00 00 00 )
.maxstack 3
ldarg.0
ldarg.1
ldarg.2
cpblk
ret
}
代码为CopyBlockUnaligned()
.method public hidebysig static void CopyBlockUnaligned(void* destination, void* source, uint32 byteCount) cil managed aggressiveinlining
{
.custom instance void System.Runtime.Versioning.NonVersionableAttribute::.ctor() = ( 01 00 00 00 )
.maxstack 3
ldarg.0
ldarg.1
ldarg.2
unaligned. 0x1
cpblk
ret
}
我们可以看到,唯一明显的区别是在 Unsafe.CopyBlockUnaligned()
实现中调用 cpblk
之前的 unaligned. 0x1
。由于我不太熟悉 IL,所以看一下 the documentation of System.Reflection.Emit.OpCodes.Unaligned
揭示了 unaligned
关键字的定义:
Indicates that an address currently atop the evaluation stack might not be aligned to the natural size of the immediately following
ldind
,stind
,ldfld
,stfld
,ldobj
,stobj
,initblk
, orcpblk
instruction.
再往下说
Unaligned specifies that the address (an unmanaged pointer,
native int
) on the stack might not be aligned to the natural size of the immediately followingldind
,stind
,ldfld
,stfld
,ldobj
,stobj
,initblk
, orcpblk
instruction. That is, for aLdind_I4
instruction the alignment of the address may not be to a 4-byte boundary. Forinitblk
andcpblk
the default alignment is architecture dependent (4-byte on 32-bit CPUs, 8-byte on 64-bit CPUs).
因此可以肯定地说 Unsafe.CopyBlock()
只应在我们知道源地址和目标地址都对齐时才使用,目前 only inofficially includes addresses returned by Marshal.AllocHGLobal()
. However the upcoming .NET 6 (currently in preview) will bring us NativeMemory
我们自己控制内存对齐,这将允许我们使用Unsafe.CopyBlock()
更自由。因此,如果不确定对齐方式,建议只使用 Unsafe.CopyBlockUnaligned()
。