哪个更快? ByVal或ByRef?

在VB.NET中,更快的方法参数, ByValByRef

此外,在运行时(RAM)消耗更多的资源?


我通读这个问题 ,但答案不适用或不够具体。

Byval和ByRef参数应该根据需求和知识来使用,而不是速度。

http://www.developer.com/net/vb/article.php/3669066

在回应斯劳的评论时,

哪个在运行时消耗更多的资源?

参数在栈上传递。 堆栈非常快,因为它的内存分配只是一个指针增量来保留一个新的“帧”或“分配logging”。 如果使用任何“堆栈”空间来传递参数,大多数.NET参数不会超过机器寄存器的大小。 事实上,基本types和指针都在堆栈上分配。 .NET中的堆栈大小限制为1 MB。 这应该给你一个parameter passing消耗less量资源的概念。

您可能会发现这一系列的文章很有意思:

通过堆栈分配提高性能(.NET内存pipe理:第2部分)

哪个更快? ByVal或ByRef。

根据你的测量环境来衡量准确和神仙是很困难的,但是我写了一个基准,我写了一个方法,上面写着:

  • 参考types – 通过ByRef:420 ms
  • 参考types – 通过ByVal:382毫秒
  • 值types – 通过ByRef:421毫秒
  • 值types – 通过ByVal:416毫秒
 Public Sub Method1(ByRef s As String) Dim c As String = s End Sub Public Sub Method2(ByVal s As String) Dim c As String = s End Sub Public Sub Method3(ByRef i As Integer) Dim x As Integer = i End Sub Public Sub Method4(ByVal i As Integer) Dim x As Integer = i End Sub Sub Main() Dim s As String = "Hello World!" Dim k As Integer = 5 Dim t As New Stopwatch t.Reset() t.Start() For i As Integer = 0 To 100000000 Method1(s) Next t.Stop() Console.WriteLine("Reference Type - ByRef " & t.ElapsedMilliseconds) t.Reset() t.Start() For i As Integer = 0 To 100000000 Method2(s) Next t.Stop() Console.WriteLine("Reference Type - ByVal " & t.ElapsedMilliseconds) t.Reset() t.Start() For i As Integer = 0 To 100000000 Method3(i) Next t.Stop() Console.WriteLine("Value Type - ByRef " & t.ElapsedMilliseconds) t.Reset() t.Start() For i As Integer = 0 To 100000000 Method4(i) Next t.Stop() Console.WriteLine("Value Type - ByVal " & t.ElapsedMilliseconds) Console.ReadKey() End Sub 

在每种方法中注释variables和赋值 –

  • 参考types – 通过ByRef:389毫秒
  • 参考types – 通过ByVal:349毫秒
  • 值types – 通过ByRef:416毫秒
  • 值types – 通过ByVal:385毫秒

可以得出结论,传递引用types(string,类)的ByVal会节省一些时间。 你也可以说传递值types(整数,字节) – ByVal会节省一些时间。

事情的macros伟计划再一次是微不足道的。 更重要的是正确使用ByVal和ByRef并理解“幕后”的情况。 在你的例程中实现的algorithm肯定会影响程序的运行时间多次。

如果你使用的是一个非常大的值types(例如Guid非常大),通过引用传递参数可能会稍微快一点。 在其他情况下,当您通过引用而不是按值传递时,可能会有更多的复制等,例如,如果您有一个字节参数,那么一个字节明显less于指针在您使用的四个或八个字节通过引用传递。

在实践中,你几乎不用担心这个。 编写可读性最高的代码,这几乎总是意味着通过值而不是参考来传递参数。 我很less使用ByRef。

如果你想提高性能,并认为ByRef会帮助你, 仔细(在你的确切的情况下)在做出承诺之前进行基准testing。

编辑:我注意到在另一个(以前接受,现在删除)答案的意见,有很多误解ByRef与ByVal意味着值types。 我有一篇关于parameter passing的文章,这些文章多年来一直很stream行 – 这是C#术语,但是同样的概念适用于VB.NET。

这取决于。 如果你传递一个对象,它已经传递了一个指针。 这就是为什么如果你传入一个ArrayList(例如),并且你的方法向ArrayList添加了一些东西,那么调用代码也会将相同的对象放入它的ArrayList中,因为它是相同的ArrayList。 唯一一次它不传递指针的时候,是当你传递一个内部数据types的variables,如一个int,或一个double,到函数中。 在这一点上,它创build一个副本。 但是,这些对象的数据大小非常小,从内存使用率或执行速度的angular度来看,这两者几乎没有什么区别。

如果您传入参考types,则ByRef较慢。

这是因为传入的是一个指向指针的指针。 任何访问对象上的字段需要解引用一个额外的指针,这将需要几个额外的时钟周期来完成。

如果你传递一个值types,那么如果结构有许多成员,那么byref可能会更快,因为它只传递一个指针而不是复制堆栈上的值。 在访问成员方面,byref会比较慢,因为它需要额外的指针解引用(sp-> pValueType-> member vs sp-> member)。

在VB大部分时间你不应该担心这一点。

在.NET中,拥有大量成员的值types很less见。 他们通常很小。 在这种情况下,传递一个值types与将多个parameter passing给一个过程没有什么不同。 例如,如果您有按值传递给Point对象的代码,则它的perf与将X和Y值作为参数的方法相同。 看到DoSomething(x为整数,y为整数)可能不会导致性能问题。 事实上,你可能永远不会三思而后行。

如果你正在为自己定义大的价值types,那么你可能应该重新考虑把它们转化为参考types。

唯一的区别是执行代码所需的指针间接指针数量的增加。 你很less需要在这个级别进行优化。 大多数情况下,你可以解决的algorithm问题,或者你的性能瓶颈是IO相关的,比如等待数据库或写入文件,在这种情况下,消除指针间接对你不会有什么帮助。

所以,我不build议把注意力集中在byval或byref上,而是build议你把注意力集中在你所需要的语义上。 一般来说,除非你特别需要byref,否则使用byval是个好主意。 它使程序更容易理解。

虽然我不太了解.NET的内部,但我会讨论我对编译语言的了解。 这不适用于引用types ,对于值types可能不完全准确。 如果你不知道值types和引用types之间的区别,你不应该读这个。 我将假设32位x86(带有32位指针)。

  • 传递小于32位的值仍然使用堆栈中的32位对象。 这个对象的一部分将是“未使用”或“填充”。 传递这样的值不会使用比传递32位值更less的内存。
  • 传递大于32位的值会比指针占用更多的堆栈空间,并且可能需要更多的复制时间。
  • 如果一个对象通过值传递,被调用者可以从堆栈中获取对象。 如果一个对象通过引用传递,被调用者必须首先从堆栈中获取对象的地址,然后从别处获取对象的值。 按价值意味着更less的获取,对吗? 那么,实际上,获取需要由调用者完成 – 但是调用者可能已经为了不同的原因而获取,在这种情况下保存了获取。
  • 很显然,对引用值的任何更改都必须保存回RAM,而可以放弃按值参数。
  • 通过值传递比通过引用只传递参数到一个局部variables而不是再次触摸它更好。

判决:

理解ByVal和ByRef实际上为您做了什么,理解价值和参考types之间的差异,而不是思考性能,这是非常重要的。 最重要的规则是使用哪种方法更适合您的代码

对于大值types(大于64位),除非传值的优点(比如简单的代码,“这很有意义”,或者接口一致性),则通过引用传递。

对于较小的值types,传递机制对性能没有太大的影响,无论如何,很难预测哪种方法会更快,因为它取决于对象的大小,调用者和被调用者如何使用对象,甚至是caching因素。 只要做你的代码是有道理的。

ByVal创buildvariables的副本,而ByRef传递一个指针。 因此,我会说ByVal比较慢(由于需要复制的时间)并使用更多的内存。

我的好奇心是根据对象和内存使用情况来检查不同的行为

结果似乎表明,ByVal总是胜利,资源取决于是否收集内存或更less(仅4.5.1)

 Public Structure rStruct Public v1 As Integer Public v2 As String End Structure Public Class tClass Public v1 As Integer Public v2 As String End Class Public Sub Method1(ByRef s As String) Dim c As String = s End Sub Public Sub Method2(ByVal s As String) Dim c As String = s End Sub Public Sub Method3(ByRef i As Integer) Dim x As Integer = i End Sub Public Sub Method4(ByVal i As Integer) Dim x As Integer = i End Sub Public Sub Method5(ByVal st As rStruct) Dim x As rStruct = st End Sub Public Sub Method6(ByRef st As rStruct) Dim x As rStruct = st End Sub Public Sub Method7(ByVal cs As tClass) Dim x As tClass = cs End Sub Public Sub Method8(ByRef cs As tClass) Dim x As tClass = cs End Sub Sub DoTest() Dim s As String = "Hello World!" Dim cs As New tClass cs.v1 = 1 cs.v2 = s Dim rt As New rStruct rt.v1 = 1 rt.v2 = s Dim k As Integer = 5 ListBox1.Items.Add("BEGIN") Dim t As New Stopwatch Dim gt As New Stopwatch If CheckBox1.Checked Then ListBox1.Items.Add("Using Garbage Collection") System.Runtime.GCSettings.LargeObjectHeapCompactionMode = System.Runtime.GCLargeObjectHeapCompactionMode.CompactOnce GC.Collect() GC.WaitForPendingFinalizers() GC.Collect() GC.GetTotalMemory(False) End If Dim d As Double = GC.GetTotalMemory(False) ListBox1.Items.Add("Free Memory: " & d) gt.Start() t.Reset() t.Start() For i As Integer = 0 To 100000000 Method1(s) Next t.Stop() ListBox1.Items.Add("Reference Type - ByRef " & t.ElapsedMilliseconds) t.Reset() t.Start() For i As Integer = 0 To 100000000 Method2(s) Next t.Stop() ListBox1.Items.Add("Reference Type - ByVal " & t.ElapsedMilliseconds) t.Reset() t.Start() For i As Integer = 0 To 100000000 Method3(i) Next t.Stop() ListBox1.Items.Add("Value Type - ByRef " & t.ElapsedMilliseconds) t.Reset() t.Start() For i As Integer = 0 To 100000000 Method4(i) Next t.Stop() ListBox1.Items.Add("Value Type - ByVal " & t.ElapsedMilliseconds) t.Reset() t.Start() For i As Integer = 0 To 100000000 Method5(rt) Next t.Stop() ListBox1.Items.Add("Structure Type - ByVal " & t.ElapsedMilliseconds) t.Reset() t.Start() For i As Integer = 0 To 100000000 Method6(rt) Next t.Stop() ListBox1.Items.Add("Structure Type - ByRef " & t.ElapsedMilliseconds) t.Reset() t.Start() For i As Integer = 0 To 100000000 Method7(cs) Next t.Stop() ListBox1.Items.Add("Class Type - ByVal " & t.ElapsedMilliseconds) t.Reset() t.Start() For i As Integer = 0 To 100000000 Method8(cs) Next t.Stop() gt.Stop() ListBox1.Items.Add("Class Type - ByRef " & t.ElapsedMilliseconds) ListBox1.Items.Add("Total time " & gt.ElapsedMilliseconds) d = GC.GetTotalMemory(True) - d ListBox1.Items.Add("Total Memory Heap consuming (bytes)" & d) ListBox1.Items.Add("END") End Sub Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click DoTest() End Sub 
Interesting Posts