メソッド引数に使用する方が速いVB.NETでは、ByVal
またはByRef
?
また、どちらが実行時に多くのリソースを消費しますか(RAM)?
この質問 を読み通しましたが、答えは当てはまらないか、十分に具体的ではありません。
Byval引数とByRef引数は、速度ではなく要件ではなく要件と知識に基づいて使用する必要があります。
http://www.developer.com/net/vb/article.php/3669066
スラウのコメントに応えて-
どちらが実行時に多くのリソースを消費しますか?
パラメータはスタックに渡されます。スタックは非常に高速です。これは、そのメモリ割り当てが、新しい「フレーム」または「割り当てレコード」を予約するための単なるポインタインクリメントであるためです。ほとんどの.NETパラメータはマシンレジスタのサイズを超えないため、パラメータの受け渡しに「スタック」スペースが使用されている場合はほとんどありません。実際、基本的な型とポインタは両方ともスタックに割り当てられます。 .NETのスタックサイズは1MBに制限されています。これにより、パラメーターの受け渡しによって消費されるリソースがどれだけ少ないかがわかります。
この一連の記事は興味深いかもしれません。
スタック割り当てによるパフォーマンスの向上(.NETメモリ管理:パート2)
どちらが速いですか? ByValまたはByRef。
正確にそして妖精を測定することはせいぜい難しいです-あなたの測定の文脈にもよるが、私が1億回メソッドを呼び出して書いたベンチマークは次のことを思いついた:
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
各メソッドでの変数と割り当てのコメント化-
参照型(文字列、クラス)を渡すことで、時間を節約できると結論付けることができます。値型(整数、バイト)を渡すと言うかもしれません-ByValは時間を節約します。
繰り返しますが、物事の壮大な計画では時間はごくわずかです。さらに重要なのは、ByValとByRefを適切に使用し、「舞台裏」で何が起こっているのかを理解することです。ルーチンに実装されているアルゴリズムは、プログラムの実行時間に何倍も影響を与えることは間違いありません。
非常に大きな値型を使用している場合(たとえば、Guidがかなり大きい場合)、参照によってパラメーターを渡す方がわずかに速い場合があります。他のケースでは、値渡しよりも参照渡しの場合moreコピーなどがある可能性があります。たとえば、バイトパラメータがある場合、 1バイトは、ポインタを参照渡しした場合にポインタが取る4バイトまたは8バイトよりも明らかに小さいです。
実際には、これについて心配する必要はほとんどありません。可能な限り読み取り可能なコードを記述します。これは、ほとんどの場合、参照ではなく値でパラメーターを渡すことを意味します。 ByRefを使用することはめったにありません。
パフォーマンスを向上させ、ByRefが役立つと思う場合は、コミットする前に(正確な状況で)pleaseベンチマークを慎重に行ってください。
編集:別の(以前は受け入れられ、現在は削除されている)回答へのコメントで、値型に関してByRefとByValの意味について多くの誤解があることに注意します。私は パラメーターの受け渡しに関する記事 を持っています。これは長年にわたって人気が高いことが証明されています。これはC#の用語にありますが、VB.NETにも同じ概念が適用されます。
場合によります。オブジェクトを渡す場合、そのオブジェクトはすでにポインタを渡しています。そのため、たとえばArrayListを渡して、メソッドがArrayListに何かを追加した場合、呼び出し元のコードも、同じArrayListであるため、渡されたArrayListに同じオブジェクトを持ちます。ポインターを渡さないのは、intやdoubleなどの組み込みデータ型の変数を関数に渡すときだけです。その時点で、コピーが作成されます。ただし、これらのオブジェクトのデータサイズは非常に小さいため、メモリ使用量や実行速度の点でどちらの方法でもほとんど違いはありません。
参照型を渡す場合、ByRefは遅くなります。
これは、渡されるのはポインタへのポインタだからです。オブジェクトのフィールドにアクセスするには、追加のポインタを逆参照する必要があります。これには、完了するまでに数クロックサイクル余分にかかります。
値の型を渡す場合、構造体に多くのメンバーがあると、スタック上の値をコピーするのではなく、単一のポインターのみを渡すため、byrefの方が高速になる可能性があります。メンバーへのアクセスに関しては、追加のポインター逆参照(sp-> pValueType-> memberとsp-> member)を実行する必要があるため、byrefは遅くなります。
ほとんどの場合、VBではこれについて心配する必要はありません。
.NETでは、多数のメンバーを持つ値型を持つことはめったにありません。それらは通常小さいです。その場合、値型を渡すことは、プロシージャに複数の引数を渡すことと同じです。たとえば、Pointオブジェクトを値で渡すコードがある場合、そのパフォーマンスは、X値とY値をパラメーターとして取るメソッドと同じになります。 DoSomething(xを整数、yを整数)を見ても、おそらくパフォーマンスの問題は発生しません。実際、あなたはおそらくそれについて二度考えたことはないでしょう。
大きな値型を自分で定義している場合は、おそらくそれらを参照型に変換することを再検討する必要があります。
他の唯一の違いは、コードの実行に必要なポインターの間接化の数の増加です。そのレベルで最適化する必要があることはめったにありません。ほとんどの場合、対処できるアルゴリズムの問題があるか、パフォーマンスのボトルネックがIO関連、たとえばデータベースの待機やファイルへの書き込みなど)のいずれかである場合、ポインターの間接参照を排除することはできませんあまり役に立ちません。
したがって、byvalまたはbyrefの方が速いかどうかに焦点を合わせるのではなく、必要なセマンティクスを提供するものに本当に焦点を当てるように勧めます。一般に、特にbyrefが必要でない限り、byvalを使用することをお勧めします。それはプログラムをはるかに理解しやすくします。
.NETの内部についてはよくわかりませんが、コンパイル言語について知っていることについて説明します。これは参照型には適用されず、値型について完全に正確ではない場合があります。値の型と参照の型の違いがわからない場合は、これを読んではいけません。 32ビットx86(32ビットポインター付き)を想定します。
評決:
パフォーマンスについて考えるよりも、ByValとByRefが実際に何をするのかを理解し、値と参照タイプの違いを理解することがはるかに重要です。一番のルールはコードに適した方法を使用するです。
大きな値型(64ビットを超える)の場合、値渡し(より単純なコード、「意味が通じる」、またはインターフェイスの一貫性など)による利点がない限り、参照渡しを行います。
小さい値型の場合、受け渡しメカニズムはパフォーマンスに大きな違いはありません。オブジェクトのサイズ、呼び出し元と呼び出し先がオブジェクトをどのように使用するか、さらにはキャッシュの考慮事項にも依存するため、どちらの方法が高速になるかを予測するのは困難です。 。コードにとって意味のあることは何でもしてください。
ByVal
は変数のコピーを作成しますが、ByRef
はポインターを渡します。したがって、ByVal
は(コピーに時間がかかるため)遅くなり、より多くのメモリを使用することになります。
私の好奇心は、オブジェクトとメモリの使用量に応じてさまざまな動作を確認することでした
結果は、ByValが常に勝つことを示しているように見えます。リソースは、収集するメモリが少ないかどうかによって異なります(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