字符串、引用和垃圾收集

本文关键字:引用 字符串 | 更新日期: 2023-09-27 18:07:53

假设您有一个对象,它有几个属性。其中一个属性是字符串:

private class MyObject
{
    public string PropertyOne {get; set;}
    ...
}

我现在基于MyObject上的内容创建一个新对象:

private class MySecondObject
{
    public string PropertyOneCopy {get; set;}
    public MySecondObject(MyObject myObject)
    {
        this.PropertyOneCopy = myObject.PropertyOne;
        ....
    }
}
在调用场景中,我们有:
private class Scenario
{
    private MySecondObject _mySecondObject;
    public void Go()
    {
        MyObject myObject = new MyObject();
        myObject.PropertyOne = "Hello, World!";
        _mySecondObject = new MySecondObject(myObject);
    }
}

MyObject的原始实例现在超出了作用域。_mySecondObject是长期存在的

我的问题是....原来的MyObject会被垃圾收集吗?如果我用this.PropertyOneCopy = String.Copy(myObject.PropertyOne);会怎么样呢?

字符串、引用和垃圾收集

以前在myObject中的对象将被正常垃圾收集,因为没有未完成的引用。

仍然有一个对string对象的引用,它曾经是myObjectPropertyOne属性的值,但这只会阻止字符串被回收,而不是整个MyObject实例。

String.Copy没有什么特别的作用,它只是作为一个构造函数,接受string实例并创建一个重复的对象(System.String没有这样的构造函数)。

肯定会被垃圾收集。即使你不使用String.Copy.

该字符串没有引用任何其他对象…相反,你拥有的是一个对象,它有一个对字符串的引用…对该字符串发生的操作与引用该字符串的其他对象无关。

例子:

如果你有对象A, B和C,它们都有一个像这样分配的字符串属性:

string s = "str";
A.Str = s;
B.Str = A.Str;
C.Str = B.Str;

等同于:

string s = "str";
A.Str = s;
B.Str = s;
C.Str = s;

当A不再使用时,它可以死亡,而不会影响其他对象,即使它们共享相同的字符串。

原来的MyObject会被垃圾收集吗?

是的,这里只有传出的引用。没办法瞒着GC。

"Hello, World!"字符串是共同拥有的,只要其中一个对象是存活的,它就会保持存活。

使用GC比你想象的要容易,你几乎不需要"帮助"。

. net垃圾收集器将回收被任何引用都无法访问的对象所使用的内存。当Go退出时,对MyObject的引用就消失了,这使得MyObject的实例可以进行垃圾收集。MyObject引用的字符串在MySecondObject中也有一个引用,这没有任何区别。

MySecondObject有一个对MyObject中的字符串的引用,而不是对MyObject-object本身的引用,因此MyObject将在您退出go函数时立即释放到GC,因此无需担心。

如果你以这种方式实现,myObject将不会被释放,直到MySecondObject被释放:

private class MySecondObject {
    private MyObject myObject;
    public string PropertyOneCopy {
        get{
            return myObject.PropertyOne;
        }
    }
    public MySecondObject(MyObject myObject)     {
        myObject = myObject.PropertyOne;
        ....
    }
}