我正在编写一个Xamarin.Android应用程序,它为代码提供语法高亮显示。它窒息了大文件。我调试了我的应用程序并在处理它时随机停止了它。令我惊讶的是,我几乎一直都停在这条线上:
var span = new ForegroundColorSpan(color);
这是我在语法高亮时经常调用的唯一一段Java代码。 This是该方法的实现,它是一个分配给int
字段的单行。显然,Xamarin的Java互操作必定是罪魁祸首。
我不确定如何解决这个问题。我尝试使用ForegroundColorSpan
为给定的Color
缓存Dictionary
,但由于Spannable API的设计方式,您无法调用SpannableString.setSpan
{{3}对于不同的范围。我还有其他选择吗?
编辑:抱歉,互操作,而不是编组。我改变了标题。
编辑2:好的,我一直在深入研究这个问题。首先,我提出了一个最小的复制品:
var list = new List<ForegroundColorSpan>();
for (int i = 0; i < 100000; i++)
{
list.Add(new ForegroundColorSpan(Color.Blue));
}
尝试在空白的Xamarin应用程序中运行它,这将需要永远。然而,真正非常奇怪的是,与迭代次数成比例的时间 。尝试将迭代次数设置为40000
,并在一秒钟内完成。尝试将其设置为50000,它将永远。如果你随机暂停调试器并检查i
,你会发现它总是在45 / 46K左右。在45K左右的元素处似乎有一个神奇的截止点,其中循环突然变得非常慢 - 而且,我的意思是每秒创建 5个新对象。
其次,我通过阅读with the same span instance文档(特别是Working with JNI)来查看构造函数在底层所做的工作,然后我手动为ForegroundColorSpan
编写了绑定,以便我可以调试它们: / p>
[Register("android/text/style/ForegroundColorSpan", DoNotGenerateAcw = true)]
internal class FastForegroundColorSpan : JavaObject
{
private static readonly IntPtr class_ref = JNIEnv.FindClass("android/text/style/ForegroundColorSpan");
private static IntPtr id_ctor_I;
[Register(".ctor", "(I)V", "")]
public unsafe FastForegroundColorSpan(int color)
: base(IntPtr.Zero, JniHandleOwnership.DoNotTransfer)
{
if (Handle != IntPtr.Zero)
{
return;
}
if (id_ctor_I == IntPtr.Zero)
{
id_ctor_I = JNIEnv.GetMethodID(class_ref, "<init>", "(I)V");
}
var args = stackalloc JValue[1];
args[0] = new JValue(color);
var handle = JNIEnv.NewObject(class_ref, id_ctor_I, args);
SetHandle(handle, JniHandleOwnership.TransferLocalRef);
}
}
我将代码改为使用new FastForegroundColorSpan
而不是new ForegroundColorSpan
。当我现在在调试器中随机停止代码时,它总是在SetHandle
处中断。我查看了this part,确实有很多东西在那里,包括对JNIEnv
和锁定/弱引用的许多互操作调用。然而,我仍然可以解释为什么应用程序总是在~45K跨度之后的某个魔术截止点减速(并且如此显着)。
答案 0 :(得分:1)
然而,真正非常奇怪的是,它所花费的时间与迭代次数并不成正比。尝试将迭代次数设置为40000,并在一秒钟内完成。尝试将其设置为50000,它将永远。
问题是你有太多的Java.lang.object实例同时存在。如果您参考Global Reference Message,您可以找到以下声明:
不幸的是,Android模拟器只允许存在2000个全局引用 一次。硬件具有52000个全局引用的更高限制。该 在仿真器上运行应用程序时,下限可能会有问题,因此 知道实例的来源非常有用。
您可以通过以下方式启用全局参考loggig(GREF)日志记录:
adb shell setprop debug.mono.log gref
您还可以参考similar case。
因此,对于解决方案,您需要删除此循环,并尝试根据您的要求解决此问题。