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

本文关键字:对象 CLI C++ | 更新日期: 2023-09-27 18:19:41

我目前正在研究使用 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 传递到程序集 B 内部的函数中。
  3. 释放对程序集 A 中对象O的引用。
  4. 程序集 B 保留对对象 O 的引用。
  5. 执行结束(即通过程序退出(。
  6. 程序集 B 释放对对象 O 的引用。

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

编辑

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

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

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

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

  • 程序集 A - (IL,我们不知道它是用什么写的(
  • 程序集 B - (IL,我们不知道它是用什么写的(
在托管对象

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

.NET 事件探查器将为您提供有关垃圾回收的一些信息,性能监视器中的回收计数也是如此。

我得出垃圾收集器在两者上工作的结论是否正确 在同一进程中运行时的代码部分(C# 和 C++/CLI(?

是的,单个垃圾回收器在一个进程中同时适用于 C# 和托管C++(。如果在一个进程中有在不同 CLR 版本下运行的代码,则每个 CLR 版本将有不同的 GC 实例

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

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

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

可以使用 .Net 探查器等工具进行监视。另请查看垃圾回收通知