Does reference types use ref save memory?

In C #, parameters for a method can be either reference types or value types. When passing reference types, a copy of the link is transmitted. Thus, if inside the method we try to reassign the passed reference to another instance of the object, the reassignment will not be visible outside the method.

To do this, C # has a ref modifier. Passing the reference type with ref actually uses the original link instead of the copy. (Correct me if I am wrong).

In this case, since we are not creating a copy of the link, do we save memory? If the method is widely called, does it improve the overall performance of the application?

Thanks!

+6
source share
4 answers

Statement

No, it is not. Anyway, this is slower due to additional search.

There is no reason to pass a reference type by reference, unless you specifically intend to assign it later.


Evidence

Since some people seem to think that the compiler passes "the most variable", look at the breakdown of this code:

using System; static class Program { static void Test(ref object o) { GC.KeepAlive(o); } static void Main(string[] args) { object temp = args; Test(ref temp); } } 

which (on x86, for simplicity):

 // Main(): // Set up the stack 00000000 push ebp // Save the base pointer 00000001 mov ebp,esp // Set up stack pointer 00000003 sub esp,8 // Reserve space for local variables 00000006 xor eax,eax // Zero out the EAX register // Copy the object reference to the local variable `temp` (I /think/) 00000008 mov dword ptr [ebp-4],eax // Copy its content to memory (temp) 0000000b mov dword ptr [ebp-8],ecx // Copy ECX (where'd it come from??) 0000000e cmp dword ptr ds:[00318D5Ch],0 // Compare this against zero 00000015 je 0000001C // Jump if it was null (?) 00000017 call 6F910029 // (Calls some internal method, idk) // THIS is where our code finally starts running 0000001c mov eax,dword ptr [ebp-8] // Copy the reference to register 0000001f mov dword ptr [ebp-4],eax // ** COPY it AGAIN to memory 00000022 lea ecx,[ebp-4] // ** Take the ADDRESS of the copy 00000025 call dword ptr ds:[00319734h] // Call the method // We're done with the call 0000002b nop // Do nothing (breakpoint helper) 0000002c mov esp,ebp // Restore stack 0000002e pop ebp // Epilogue 0000002f ret // Return 

It was an optimized compilation of code. It is clear that there is the address of the variable passed, and not "the variable itself."

+12
source

Yes, there is a reason: If you want to reassign this value. There is no difference in value types and reference types.

See the following example:

 class A { public int B {get;set;} } void ReassignA(A a) { Console.WriteLine(aB); a = new A {B = 2}; Console.WriteLine(aB); } // ... A a = new A { B = 1 }; ReassignA(a); Console.WriteLine(aB); 

This will output:

 1 2 1 

Performance, however, has nothing to do with it. It will be real micro-optimization.

+5
source

DISTRIBUTION OF IMAGES Example of Mehridad (GENERAL VERSIONS)

I will try to understand Mehrdad a little deeper, for people like me who do not read assembly code very well. This code can be written in Visual Studio when we debbuging by clicking Debug -> Windows -> Dissasembly.

VERSION using REF

Source:

  namespace RefTest { class Program { static void Test(ref object o) { GC.KeepAlive(o); } static void Main(string[] args) { object temp = args; Test(ref temp); } } } 

Assembly Language (x86) (only showing the part that is different):

  object temp = args; 00000030 mov eax,dword ptr [ebp-3Ch] 00000033 mov dword ptr [ebp-40h],eax Test(ref temp); 00000036 lea ecx,[ebp-40h] //loads temp address address on ecx? 00000039 call FD30B000 0000003e nop } 

VERSION WITHOUT REF.

Source:

  namespace RefTest { class Program { static void Test(object o) { GC.KeepAlive(o); } static void Main(string[] args) { object temp = args; Test(temp); } } } 

Assembly Language (x86) (only showing the part that is different):

  object temp = args; 00000035 mov eax,dword ptr [ebp-3Ch] 00000038 mov dword ptr [ebp-40h],eax Test(temp); 0000003b mov ecx,dword ptr [ebp-40h] //move temp address to ecx? 0000003e call FD30B000 00000043 nop } 

In addition to the commented line, the code for both versions is the same: with ref, the function call precedes the LEA instruction, without a link to the link we have a simpler MOV instruction. After executing this line, LEA loaded the ecx register with a pointer to an object pointer, while MOV loaded ecx with an object pointer. This means that the FD30B000 routine (pointing to our test function) in the first case will have to make additional memory access to access the object. If we check the build code for each released version of this function, we will see that at some point (in fact, the only line that differs from the two versions) additional access is provided:

 static void Test(ref object o) { GC.KeepAlive(o); } ... 00000025 mov eax,dword ptr [ebp-3Ch] 00000028 mov ecx,dword ptr [eax] ... 

So far, a function without ref can go directly to the object:

 static void Test(object o) { GC.KeepAlive(o); } ... 00000025 mov ecx,dword ptr [ebp-3Ch] ... 

Hope this helps.

+4
source

Passing a reference type by value does not copy the object. It only creates a new link to an existing object. Therefore, you should not pass it by reference, if you really need it.

0
source

Source: https://habr.com/ru/post/895725/


All Articles