Sweetness
Sweetness

Reputation: 116

Persistent memory confusion

I'm trying to understand persistent memory in C# and don't know why this code is not keeping the change made in one of the functions.

using System;
using System.Runtime.InteropServices;

public class Test2
{
    public struct value
    {
        public int sz;
    }

    public static void Main(string[] args)
    {
        one foo1 = new one(one_full);
        two foo2 = new two(two_full);
        make_calls(foo1, foo2);
    }

    public delegate void one(IntPtr ctx);
    public static void one_full(IntPtr ctx)
    {
        /* set sz and see if persists */
        GCHandle gch = GCHandle.FromIntPtr(ctx);
        value val = (value)gch.Target;

        val.sz = 6;
        Console.WriteLine("Changed sz to be 6");
    }

    public delegate void two(IntPtr ctx);
    public static void two_full(IntPtr ctx)
    {
        GCHandle gch = GCHandle.FromIntPtr(ctx);
        value val = (value)gch.Target;

        Console.Write("sz is = ");
        Console.WriteLine(val.sz);
    }

    public static void make_calls(one f_one, two f_two)
    {
        value test = new value();
        test.sz = 0;

        IntPtr ptr = GCHandle.ToIntPtr(GCHandle.Alloc(test));
        f_one(ptr);
        f_two(ptr);
    }
}

I know it's missing the free at the end but that is just leading to messy memory management.... I'm looking for if someone can help me out and explain why sz does not stay as the value 6 for when the second function is called...

The output when ran is:

Changed sz to be 6
sz is = 0

Upvotes: 2

Views: 113

Answers (2)

Hamid Pourjam
Hamid Pourjam

Reputation: 20754

Becuase value is a sturct and structs are not reference types. when you have an instance of a struct and var b = instanceOfStruct then b is a new struct not a reference to instanceOfStruct. Chaning values in b does not reflect to instanceOfStruct.

In your code:

value val = (value)gch.Target;

will create a new instance of value struct which has same values as the structs that gch.Target point to it. Changing val does not change the struct behind gch.Target. The problem is because of a confusion between value types and reference types in C#. If you change value type to a class instead of struct then you will get the desired result. You can also use dynamic to modify the struct which is target of the handle:

dynamic val = gch.Target;
val.sz = 6;

Upvotes: 1

Jakub Lortz
Jakub Lortz

Reputation: 14894

It's all because value is a struct.

GCHandle.Alloc takes an object parameter, so if you pass a struct, it has to be boxed.

Later when you use

value val = (value)gch.Target;

it has to be unboxed, so a copy of it is stored in val. Any modifications you make later are made on the copy, not on the boxed struct.

It has nothing to do with GCHandle, it's how value types (structs) work in C#. That's why it's recommended to make value types immutable.

Upvotes: 2

Related Questions