views:

3136

answers:

7

In VB.NET, which is faster to use for method arguments, ByVal or ByRef?

Also, which consumes more resources at runtime? (RAM)


Edit: I read through this question, but the answers are not applicable or specific enough.

A: 

ByVal creates a copy of the variable, whereas ByRef passes a pointer. I would therefore say that ByVal is slower (due to time it takes to copy) and uses more memory.

Colin
That's just guesswork though. Consider a byte parameter - and then consider the size of a pointer...
Jon Skeet
In, fact consider any type whose size is less than the size of a pointer. (A Short, for example)
Eduardo León
Now imagine a string that contains the contents of a large text file. No guesswork ByRef is faster. I will guess that it doesn't really matter when the sizes are small.
bruceatk
+8  A: 

It depends. If you are passing an object, it is already passing a pointer. That's why if you pass in an ArrayList (for instance) and your method adds somthing to the ArrayList, then the calling code also has the same object into it's ArrayList, that was passed in, because it's the same ArrayList. The only time that it doesn't pass a pointer, is when you pass a variable with an intrinsic data type, like an int, or a double, into the function. At that point, it creates a copy. However, the data size of these objects is so small, that it would hardly make a difference either way, in terms of memory usage or speed of execution.

Kibbee
+30  A: 
No votes left today, unfortunately - but otherwise a big +1 from me.
Jon Skeet
Here, here. If you're looking to gain perf by changing this, you probably don't know what the hell you're doing.
ctacke
answer is right but that wasn't the question was it? Why do we assume that question opener is not aware of that anyway?
dr. evil
+7  A: 

If you're using a very large value type (Guid is pretty big, for example) it may be very slightly faster to pass a parameter by reference. In other cases, there may be more copying etc when you pass by reference than by value - for instance, if you've got a byte parameter, then one byte is clearly less than the four or eight bytes that the pointer would take if you passed it by reference.

In practice, you should almost never worry about this. Write the most readable code possible, which almost always means passing parameters by value instead of reference. I use ByRef very rarely.

If you want to improve performance and think that ByRef will help you, please benchmark it carefully (in your exact situation) before committing to it.

EDIT: I note in the comments to another (previously accepted, now deleted) answer that there's a great deal of misunderstanding about what ByRef vs ByVal means when it comes to value types. I have an article about parameter passing which has proved popular over the years - it's in C# terminology, but the same concepts apply to VB.NET.

Jon Skeet
A: 

As per comments on my previous answer, Jon is in fact correct and thus his answer should be accepted over mine...

BenAlabaster
It's probably worth Jeremy waiting a while before accepting *any* answers. I suspect people with more energy than me may want to add benchmarks etc. I'm meant to be watching a film with my wife :)
Jon Skeet
lol - then go watch a film and let the rest of the software industry make do without you for an evening :P
BenAlabaster
+3  A: 

If you are passing in a reference type, ByRef is slower.

This is because what gets passed in is a pointer to a pointer. Any access to fields on the object requires dereferencing an extra pointer , which will take a few extra clock cycles to complete.

If you are passing a value type, then byref may be faster if the structure has many members, because it only passes a single pointer rather than copying the values on the stack. In terms of accessing members, byref will be slower because it needs to do an extra pointer dereference (sp->pValueType->member vs sp->member).

Most of the time in VB you shouldn't have to worry about this.

In .NET it is rare to have value types with a large number of members. They are usually small. In that case, passing in a value type is no different than passing in multiple arguments to a procedure. For example, if you had code that passed in a Point object by value, it's perf would be the same as a method that took X and Y values as parameters. Seeing DoSomething(x as integer, y as integer) would probably not cause perf concerns. In fact, you would probably never think twice about it.

If you are defining large value types your self, then you should probably reconsider turning them into reference types.

The only other difference is the increase in the number of pointer indirections required to execute the code. It is rare that you ever need to optimize at that level. Most of the time, there are either algorithmic issues you can address, or your perf bottleneck is IO related, such as waiting for a database or writing to a file, in which case eliminating pointer indirections isn't going to help you much.

So, instead of focusing on wheter byval or byref is faster, I would recommend that you should really be focusing on what gives you the semantics that you need. In general, it's good idea to use byval unless you specifically need byref. It makes the program much easier to understand.

Scott Wisniewski
A: 

While I don't know much about the internals of .NET, I'll discuss what I know about compiled languages. This does not apply to reference types, and may not be completely accurate about value types. If you don't know the difference between value types and reference types, you shouldn't read this. I'll assume 32-bit x86 (with 32-bit pointers).

  • Passing values smaller than 32-bits still uses a 32-bit object on the stack. Part of this object will be "unused" or "padding". Passing such values doesn't use less memory than passing 32-bit values.
  • Passing values larger than 32-bits will use more stack space than a pointer, and probably more copying time.
  • If an object is passed by value, the callee can fetch the object from the stack. If an object is passed by reference, the callee must first fetch the object's address from the stack, and then fetch the object's value from elsewhere. By value means one less fetch, right? Well, actually the fetch needs to be done by the caller - however the caller may have already had to fetch for different reasons in which case a fetch is saved.
  • Obviously any changes made to a by-reference value must be saved back to RAM, whereas a by-value parameter can be discarded.
  • It's better to pass by value, than to pass by reference only to copy the parameter into a local variable and not touch it again.

The verdict:

It's much more important to understand what ByVal and ByRef actually do for you, and understand the difference between value and reference types, than to think about performance. The number one rule is to use whichever method is more appropriate to your code.

For large value types (more than 64 bits), pass by reference unless there is an advantage to passing by value (such as simpler code, "it just makes sense", or interface consistency).

For smaller value types, the passing mechanism doesn't make much difference to performance, and anyway it's hard to predict which method will be faster, since it depends on the object size, how the caller and callee use the object, and even cache considerations. Just do whatever makes sense for your code.

Artelius