【问题标题】:Return Value memory scope返回值内存范围
【发布时间】:2011-04-21 00:35:56
【问题描述】:

如果我有这样的方法:

public SomeObject GetObject(int ID){

    SomeObject obj1 = new SomeObject();

    obj1.ID = ID;

    return obj1;
}

如果我使用这样的方法:

SomeObject obj2 = GetObject(4);

obj2 只是在内存中对obj1 的引用,还是会被复制到内存中并且存在两个完整的对象?

如果后者为真,那么 GC 何时会从内存中删除 obj1

【问题讨论】:

    标签: c# memory garbage-collection return-value


    【解决方案1】:

    这取决于类型。有值类型和引用类型。

    Value types 将值本身存储在内存中,每次传递它时,你只是在复制值(因此,值类型),除非你使用类似public void Test(ref int x) 的东西。 ref 存在的事实意味着通过引用传递整数。

    当你有一个reference type(对象)的变量时,你基本上只是持有一个指针。所以它会传递对象的相同引用。

    您可以通过扩展您的代码来执行以下操作来确认这一点:

    obj2.ID = 3;
    Console.WriteLine(obj1.ID); // => 3
    

    当不再有对对象的任何引用时,obj1(或对象本身,因为 obj1 只是一个引用)将被 GC'd。

    【讨论】:

      【解决方案2】:

      如果 SomeObject 从ValueType 派生,则位于 GetObject 范围内的实例将在返回后立即销毁,并创建一个新实例并将其分配给 obj2。 如果 SomeObject 不是 ValueType(也称为引用类型),则只会返回它的引用,因此您最终会得到 1 个实例。 无法预测 GC 何时会销毁对象,但是,GC 只会销毁引用类型,当代码执行超出其范围时,ValueTypes 会自动销毁。

      【讨论】:

        【解决方案3】:

        obj2 是否只是内存中对 obj1 的引用
        是(假设它不是值类型)

        但是要注意一点:对象总是在参数中通过值传递,所以如果你改变 GetObject:

        public class SomeObject
        {
            public string Name { get; set; }
            public int ID { get; set; }
            public SomeObject() { ID = 1; Name = "test"; }
        }
        
        static void Main(string[] args)
        {
            SomeObject obj1 = new SomeObject();
            GetObject(obj1, 2);
        
            Console.WriteLine(obj1.ID); // prints 1
            Console.Read();
        }
        
        public static void GetObject(SomeObject obj1, int id)
        {
            var obj = new SomeObject();
            obj.ID = id;
            obj.Name = "";
        
            obj1 = obj;
        }
        

        【讨论】:

        • 对象实际上并不是“按值”传递的。它们的引用是按值传递的。
        • @minitech 我不确定我说他们不是
        • 这只是令人困惑,因为问题是询问是否正在复制对象的内容,而您的示例与此无关。
        【解决方案4】:

        假设SomeObject 是一个类,该方法将返回对其创建的对象实例的引用。

        对象实例不会被复制,只有一个实例。在 .NET 中不会进行对象复制,除非您特别要求进行复制,例如通过调用 Clone 方法。

        在谈论引用类型时,重要的是要记住对象实例、实例引用和保存引用的变量之间的区别。变量obj1 持有对实例的引用,并且该变量在方法的堆栈帧中分配,因此当您退出方法时它会消失。引用是从方法中返回的,但此时该变量已不存在。

        【讨论】:

          【解决方案5】:

          它将是内存中对obj1 的引用,假设obj1class 而不是struct

          【讨论】:

            【解决方案6】:

            如果某个对象是引用类型,那么您是正确的,因为如果 SomeObject 是值类型,您将获得一个副本,那么您将获得一个引用副本。稍后,当垃圾收集器决定要释放内存时,垃圾收集器会清理 SomeObject。但是,您可以通过调用 GC.collect 来强制 GC 处理

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2020-10-12
              • 2019-05-20
              • 1970-01-01
              • 2022-07-05
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多