Xamarin Android垃圾收集算法

Eri*_*tta 4 mono android garbage-collection xamarin.android xamarin

我正在阅读Xamarin.Android垃圾收集文档,关于通过减少引用的实例来帮助GC更好地执行.

该部分首先说:

每当在GC期间扫描Java.Lang.Object类型或子类的实例时,也必须扫描实例引用的整个对象图.对象图是"根实例"引用的对象实例集,以及根实例引用的所有内容,递归地引用.

......我明白了.

然后它将显示继承自标准Activity类的自定义类.此自定义活动类有一个字段,该字段是在构造函数中初始化为具有10,000个字符串的字符串列表.据说这很糟糕,因为在GC期间必须扫描所有10,000个实例的可达性.我也理解.

我不清楚的部分是建议的修复:它说该List<string>字段应该移动到另一个不继承的类,Java.Lang.Object然后该类的实例应该从活动中引用,就像引用列表一样之前.

我的问题:当实例总数仍为10,000时,如何将字段深入到对象图中有助于GC,并且开头段落表示最终会扫描它们,因为该过程是递归的?

作为旁注,我也在(在这里)阅读Mono在Android上使用的SGen GC,并且对象图遍历过程被描述为从GC根开始的广度优先.这解释了10,000项目列表如何在检查每个项目时导致更长的GC暂停,但仍然没有解释如何将该列表更深入地移动到图形中将有所帮助,因为GC会在深入到图形时最终扫描它.

Jon*_*las 11

我会尽力解释这一点,而且我离这里的专家不远,所以任何想要加入的人都请这样做.

当我们提到做a时peer walk,我们正在查找任何roots并遍历实时参考图以查看可到达的内容和不可访问的内容:

在此输入图像描述

根对象:

  • 静态字段/属性指向的对象
  • 每个托管线程的堆栈上的对象
  • 已传递到本机API的对象

基本上你必须处理两个管理的GC.我们将其称为Xamarin GC和Android GC以供参考.

在此输入图像描述

Xamarin.Android peer objects用于引用Android JVM中已知的本机Java对象.他们实现了一个核心接口:

namespace Android.Runtime
{
    public interface IJavaObject : IDisposable
    {
        // JNI reference to the Java object it is wrapping. 
        // Also known as a pointer to the JVM object
        public IntPtr Handle { get; set; }
        ...
    }
}
Run Code Online (Sandbox Code Playgroud)

每当我们有一个IJavaObject继承的对象时,它将通过上面的JNI句柄保留一个强引用,以确保只要被管理对象处于活动状态,它就会保持活动状态.

想一想:

IJavaObject- > IntPtr Handle- >Java Object

在GC术语中,它将表示如下:

Allocated and collected by Xamarin GC- > GC Root- >Allocated and collected by Android GC

然后我们在Xamarin.Android中有一个GC过程:

在此输入图像描述

当GC运行时,您可以看到它将用弱引用替换强JNI句柄,然后调用将收集Java对象的Android GC.因此,peers会扫描任何关系以确保它们在JVM中进行镜像.这样可以防止这些对象过早收集.

一旦发生这种情况,我们运行Android GC,当它完成时,它将遍历对等对象并检查弱引用.

  • 如果一个对象消失了,我们会在C#端收集它
  • 如果对象仍然存在,那么我们将弱引用更改回强JNI句柄

因此,每次GC在peer对象上运行时,都需要检查和更新此图.这就是为什么它对这些包装类型对象来说要慢得多,因为必须从对等对象开始扫描整个对象图.

因此,当我们的peer对象使用了重要的对象图时,我们可以通过在peer类外移动引用的存储来帮助GC过程.这通常由rooting我们独立于同行的参考完成.由于它不是作为字段存储的,因此GC不会尝试在对象图上进行关系遍历.

如前所述,在您注意到长GC之前,这不是一个需要担心的大问题.然后,您可以将其用作解决方案.

图片来源:Xamarin大学(https://www.xamarin.com/university)