跨C#和C ++ / CLI对象的垃圾收集

我目前正在研究使用C ++ / CLI来弥补托管C#和本机非托管C ++代码之间的差距。 我想要解决的一个特殊问题是C#和C ++中不同的数据类型的转换。

在阅读使用这种桥接方法以及所涉及的性能影响的同时,我想知道垃圾收集如何工作。 具体来说,如果垃圾收集器在“另一侧”被引用/销毁,它们将如何处理在任一侧创建的对象的清理。

到目前为止,我已经阅读了有关StackOverflow和MSDN的各种文章和论坛问题,这让我相信垃圾收集器在同一个进程中运行时应该跨两种类型的代码工作 – 即如果一个对象是用C#创建的,传递给C ++ / CLI桥接器,在双方的引用不再使用之前不会收集它。

在这种情况下,我的问题分为三个部分:

  1. 我是否正确地得出结论,当在同一个进程中运行时,垃圾收集器可以跨代码的两个部分(C#和C ++ / CLI)工作?
  2. 关于1:在这种情况下它是如何工作的(特别是在清理两个代码库引用的对象方面)。
  3. 是否有关于如何监视垃圾收集器活动的建议 – 即编写测试以检查垃圾收集何时发生; 或监视垃圾收集器本身的程序。

我已经对垃圾收集器的工作原理有了一些了解,所以我的问题特定于以下场景:

组件

  • 大会A – (用C#编写)
  • 程序集B – (用C ++ / CLI编写)

程序执行

  1. 对象O程序集A中创建。
  2. 对象O被传递到Assembly B内的一个函数中。
  3. 已发布对程序集A中对象O引用。
  4. 程序集B保持对对象O引用。
  5. 执行结束(即通过程序退出)。
  6. 程序集B释放对象O引用。

提前感谢您对此问题的任何想法。 如果需要进一步的信息或者某些内容不够清楚,请告诉我。

编辑

根据要求,我已经写了一个我想要描述的场景的粗略示例。 可以在PasteBin上找到C#和C ++ / CLI代码。

当代码实际运行时,它们都不是C#或C ++ / CLI。 所有这些都是来自C#和C ++ / CLI的IL以及来自您正在与之互操作的本机代码的机器代码。

因此,您可以将部分问题重写为:

  • 大会A – (IL和我们不知道它写的是什么)
  • 大会B – (IL,我们不知道它写的是什么)

在托管对象中,除非您使用一种机制来阻止它(GC.KeepAlive),否则它们将按照相同的规则进行垃圾回收。 所有这些都可以在内存中移动,除非你将它们固定(因为你将地址传递给非托管代码)。

.NET Profiler将为您提供有关垃圾收集的一些信息,以及性能监视器中的收集计数。

我是否正确地得出结论,当在同一个进程中运行时,垃圾收集器可以跨代码的两个部分(C#和C ++ / CLI)工作?

是的,单个垃圾收集器在一个进程内工作(C#和托管C ++)。 如果在一个进程中有代码在不同的CLR版本下运行,那么每个CLR版本将有不同的GC实例

关于1:在这种情况下它是如何工作的(特别是在清理两个代码库引用的对象方面)。

我认为对于GC,如果代码是托管C#或C ++ / CLI并不重要(请注意,GC只管理C#和托管C ++代码而不是本机C ++)。 它将以自己的方式工作,而不考虑底层的代码类型。 关于释放内存,只要无法再引用对象,GC就会这样做。 因此,只要存在引用变量的内容,无论汇编如何都不会收集它。 对于本机C ++代码,您必须手动释放每个动态分配的内存

是否有关于如何监视垃圾收集器活动的建议 – 即编写测试以检查垃圾收集何时发生; 或监视垃圾收集器本身的程序。

您可以使用.Net Profiler等工具进行监控。 另请参阅垃圾收集通知