12

From my understanding C++/CX doesn't use garbage collection, it use a reference counted approach instead.

The problem with reference counting is that it cannot dispose of cycles. Cycles are usually solved using weak references, such as weak_ptr in standard C++.

But I cannot find a way in C++/CX to explicitly specify a weak reference. From that I would assume that this is handled by C++/CX itself. I am wondering how C++/CX would solve this.

For instance, look at the following code:

ref class Foo
{
public:
    Bar^ bar;
};

ref class Bar
{
public:
    Foo^ foo;
};

ref class App
{
public:
    virtual void OnLaunched(LaunchActivatedEventArgs^ args)
    {
        Foo^ foo = ref new Foo();
        Bar^ bar = ref new Bar();
        foo.bar = bar;
        bar.foo = foo;
    }
};

How does C++/CX detect this cycle?

How does C++/CX solve this cycle?

How does C++/CX decide which one of these objects should be the "root object" and which one should be the "weak reference"?

4

6 回答 6

12

简短回答:不,C++/CX 不检测和解决对象循环。

长答案:WinRT 本身具有弱引用的标准机制。在 ABI 级别,这是根据接口IWeakReference和定义的IWeakReferenceSource,您可以在“%ProgramFiles%\Windows Kits\8.0\Include\winrt\WeakReference.idl”中看到。

在 C++/CX 中,所有的类都会自动实现IWeakReferenceSource,因此它们的所有实例都可以被弱引用。要获取和存储对对象的弱引用,您应该使用辅助类Platform::WeakReference(在 vccorlib.h 中定义):

Foo^ foo = ref new Foo;
Platform::WeakReference weakRef(foo);

要取回对象,请使用Resolve<T>

foo = weakRef.Resolve<Foo>();

像往常一样,你会得到nullptr对象已经被销毁。

除此之外,一个实例的WeakReference行为或多或少像一个智能指针——它是可复制的、可移动的、可比较的、可赋值的nullptr,具有到未指定布尔类型的隐式转换等。

请注意,从 VS11 Beta 开始,WeakReference如果您尝试使用 IDE Intellisense,它将犹豫不决,并用曲线等下划线。尽管如此,编译器仍然可以很好地处理它们。

于 2011-09-17T08:05:09.990 回答
1

查看 SDK 中的 Include\winrt\WeakReference.h。它定义了可用于此目的的 IWeakReference。

于 2011-09-16T22:06:12.787 回答
0

正如 Pavel Minaev 所说,WinRT 有一个标准的弱引用机制:IWeakReferenceSource/IWeakReference接口、WRL::WeakRef助手类等等。

不幸的是,通过定义的类ref class没有实现IWeakReferenceSource,至少在这个 Developer Preview 版本中,我找不到任何方法来添加这个接口。

一种可能的解决方法是在“本机”C++ 中实现 WinRT 类而不使用 C++/CX 扩展。WRL 框架大大简化了这项任务(它对 WinRT 的作用与 ATL 对 COM 的作用相同)。

有一个 WinRT 示例(“DLL 服务器创作”示例)展示了如何在不使用 . 的情况下实现 WinRT 对象ref。默认情况下,继承自的类会WRL::RuntimeClass<Interface>自动实现IWeakReferenceSource并因此提供弱引用。

于 2011-10-05T16:21:50.340 回答
0

它将与旧的 COM 编程方式、手动思考和添加显式 decref 调用相同。

于 2011-09-16T07:23:47.950 回答
0

Mozilla XPCOM 实现了 Bacon 的方法,如果需要,这种方法在某种程度上可以移植到 WinRT。一般来说,避免跟踪垃圾收集器是一件好事。开发人员仍有很多泄漏内存的方法,所以最好不要误入歧途。此外,从控制的角度来看,循环所有权没有意义。这就像蒙乔森抓住自己的头发把自己从泥潭中拉出来,让自己漂浮在空中。每一个对象的存在都必须有一个理由,而引用计数就是这个理由的体现。另一种表现形式是修改权,它产生了高度依赖于引用计数器可用性的强大的写时复制技术。在只有跟踪垃圾收集的环境中,要么必须执行可变数据结构的深层复制以保护其免受不需要的突变,要么使用不可变数据结构,对小的深层变化有很大的惩罚。或者来回转换可变和不可变数据结构。另外,估计跟踪垃圾收集只有在有 5 倍所需 RAM 可用时才能正常工作(深度复制的副本不计)。相比之下,保守的分配器使用 2 倍所需的 RAM(由于碎片而浪费)。不要被欺骗,复制垃圾收集器只会使分配更快,但为了达到可比的性能,比引用计数的保守垃圾收集器浪费 2.5 倍的 RAM。

看看苹果。他们将 TGC 作为可选功能引入到 Objective-C 2.0 中,但随后弃用了它,大量的 iPhone 应用程序在没有它的情况下也能正常工作。iPhone 以出色的用户体验和较长的电池充电时间而闻名。Windows 10 在我的 4Gb RAM PC 上死机,而 Mac OS X 10.4.10 Hackintosh 在 1Gb RAM 上运行得非常顺利。也许这在某种程度上是相关的,你不这么认为吗?也许内存在某处意外泄漏,但与冻结和巨大的 RAM 消耗相比,最终很难观察到。

巨大的 RAM 消耗使程序交换到磁盘,如果它们交换到磁盘然后开始跟踪垃圾收集,交换的页面将全部返回到 RAM,并且将交换的页面移回 RAM 非常慢。此外,这样做时,必须抢占其他应用程序的页面以交换文件。众所周知,跟踪垃圾收集的应用程序使用 2.5 倍的 RAM,因此这些应用程序有 2.5 倍的机会进行交换。突然,另一个应用程序也将启动垃圾收集,并且必须将交换的页面返回 RAM,抢占另一个应用程序的页面。它像永续移动一样去来去去,反之亦然。普通永动机无限地凭空产生能量,永动机反之亦然无限浪费能量。跟踪垃圾收集是一种永无止境的算法。它不时以启发式方式启动,并且只有在运气好时才知道何时完成。也许这一次我们会很幸运地收集到一些东西,也许是第二次,也许是第三次。你离开PC很长一段时间,希望它最终会完成它的业务并最终让你工作,但这个业务永远不会结束。突然,两个应用程序同时运行跟踪垃圾收集并开始竞争未交换的 RAM。跟踪垃圾收集可能会对同一页面进行多次后续访问,因此一个页面可以多次往返交换。在办公环境中,只有老板的 PC 可能有很多 RAM,其他 PC 则尽可能便宜。此外,杀毒软件被强行部署到每台办公电脑上,办公人员无法摆脱它。防病毒软件会为内存中的签名保留 RAM,使其更加稀缺,并且还会检查每个 I/O,包括交换文件驱动冻结以完全疯狂。那就是地球上的地狱所在。

我问追踪垃圾收集器的倡导者他们是否可以像我一样观察到冻结,结果发现他们在他们的 PC 中放入了大量 RAM(就像笔记本电脑上的 16Gb !!!),在单用户模式下使用它,然后进行垃圾收集这种方式对他们来说很好。在地狱中,他们将不得不在最便宜的办公 PC 上进行开发,并强制部署了防病毒软件。

所以我建议你不要只看循环收集问题。学会爱上引用计数,享受它,让用户喜欢你的苗条程序。充分利用引用计数。嵌套结构的强大的写时复制。带有包装连接的数据库连接池,当不再引用它们的包装器时,连接会立即返回到池中。网络透明。RAII。

如果您真的没有其他选择,请向 Mozilla XPCOM 借用。顺便说一句,在 Windows 操作系统上,Mozilla XPCOM 被告知具有与 Microsoft COM 相同的 ABI,但不确定。

于 2016-11-22T03:52:55.497 回答
-5

这些不是 WinRT 对象,它们是您的自定义类型的对象。因为您已ref class使用 C++/CLI 语法将它们声明为 .NET 引用类型 ( ),所以它们像所有 .NET 引用类型一样通过可达性测试而不是引用计数进行垃圾收集。

Win32 对象一直被引用计数,因此 WinRT 似乎没有改变任何东西。它只是为您提供了 C++ RAII 类,在 Win32 下,程序员编写了自己的包装器来利用 RAII。

于 2011-09-16T22:11:21.220 回答