.net 如何使用weak GCHandle来监视在垃圾收集之后被收集的对象

ttcibm8c  于 2023-08-08  发布在  .NET
关注(0)|答案(1)|浏览(119)

我想使用GCHandle来监视对象是否在GC之后被收集,所以我在Release模式下运行下面的代码,而不是在Deubg模式下(它将对象的生命周期延长到方法的末尾)

internal class Program
{
    static void Main(string[] args)
    {
        var person = new Person();
        var handle = GCHandle.Alloc(person, GCHandleType.Weak);

        person = null; // don't really need to set it to null because of JIT compiler's feature, but I still set it null here

        GC.Collect();  // <------------------ person object should be GCed as `person` is not referenced anymore

        Console.WriteLine(handle.IsAllocated);  // print 'true'
        Console.ReadLine();
    }
}

public class Person { }

并且输出仍然打印true,这意味着person在GC之后仍然存在,这怎么可能呢?更让我困惑的是,GCHandle和它的内部字段IntPtr都是结构体,这意味着IntPtr在GC之后不会为零,因为IntPtr的前一个值已经存储在用户的堆栈中,那么如何使用GCHandleType.Weak正确地监视它呢?

dy2hfwbg

dy2hfwbg1#

GC确实收集了Person对象,但是“IsAllocated”引用的是句柄而不是person对象。

using System;
using System.Runtime.InteropServices;

namespace ConsoleApp12
{
    internal class Program
    {
        static void Main(string[] args)
        {
            var person = new Person();
            var handle = GCHandle.Alloc(person, GCHandleType.Weak);

            Console.WriteLine("Collected");

            GC.Collect();  // <------------------ person object will be collected now

            Console.WriteLine(handle.IsAllocated);  // print 'true'

            handle.Free();

            Console.WriteLine(handle.IsAllocated);  // print 'false'

            Console.ReadLine();
        }
    }

    public class Person
    {
        ~Person()
        {
            Console.WriteLine("Destroyed");
        }
    }
}

输出:

Collected
True
Destroyed
True
False

相关问题