Monodroid:执行完整的GC

我尝试创建我的小粒子系统。 我有粒子列表的粒子管理器,并在canvas上绘制我的粒子。 我只是在init()函数中创建了一些像Paint等新对象! 如果粒度<0,我将其删除:

for (int particle = 0; particle  0 ? true : false { particles[particle] = null; //here I tried all variations like //((IDisposable)particles[particle]).Dispose(); //GC.SuppressFinalize(particles[particle]); //System.GC.ReRegisterForFinalize(particles[particle]); //((Java.Lang.Object)particles[particle]).Dispose(); and etc particles.Remove(particles[particle]); } 

然后我创建新的粒子并将其添加到我的列表中。 我在日志中看到的内容:

 GC cleanup summary: 1063 objects tested - resurrecting 1002. GC cleanup summary: 1053 objects tested - resurrecting 992. ... GC cleanup summary: 1052 objects tested - resurrecting 988. 46800 outstanding GREFs. Performing a full GC! 

然后我在渲染线程中有10-15(!!!)秒暂停! 我阅读官方文档,但它没有任何解决方案。 我分析并比较了我的代码与单声道JetBoy示例,但JetBoy的日志没有关于GC的任何内容。 虽然我用JetBoy的例子编写了我的程序。 如何解决完整的GC问题?


编辑:MainThread.cs

 public override void Run() { Log.Verbose("Run()", "r"); Canvas c; while (mRun) { c = null; mPassedTime = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond; if (mTimerTask == null) { mTimerTask = new CountDownTimerTask(this); mTimer.Schedule(mTimerTask, mTaskIntervalInMillis); } try { c = mSurfaceHolder.LockCanvas(null); lock (mSurfaceHolder) DoDrawRunning(c); } finally { if (c != null) mSurfaceHolder.UnlockCanvasAndPost(c); } } } private void DoDrawRunning(Canvas canvas) { #region particles for (int eng = 0; eng < engines.Count; eng++) { engines[eng].Update(); engines[eng].Draw(canvas); } #endregion } 

ParticleEnginee.cs

 public void Update() { if (particles.Count < maxTotal) { for (int i = 0; i < total; i++) { if (addNewB) particles.Add(GenerateNewParticle()); // return new Particle } } for (int particle = 0; particle  0 ? particles.RemoveAt(particle); } } public void Draw(Canvas canvas) { for (int j = 0; j < 3; j++) // 3 particle color-levels draw for (int index = 0; index < particles.Count; index++) particles[index].Draw(canvas, j); } 

Particle.cs

 public void Draw(Canvas canvas) { mPaint.StrokeWidth = mSize; mPaint.Color = Color.Blue; canvas.DrawPoint(posX, posY, mPaint); } 

主要问题是您有多个Java.Lang.Object实例同时处于活动状态,因为每个Java.Lang.Object实例都会导致JNI全局引用计数,这也会导致GC开销。 想降低GC开销吗? 减少您使用的GREF数量。

您可以通过启用gref日志记录来跟踪GREF计数

 adb shell setprop debug.mono.log gref 

我假设Particle是一个Java.Lang.Object子类,这意味着你至少有一个 particles.Count GREFs存活。

解决方案是不要使Particle成为Java.Lang.Object子类,并以任何方式改变您的体系结构以确保Particle不是一个。

如果Particle不是Java.Lang.Object实例,那么我们缺乏足够的信息来重现问题并提出解决方案。 GREF日志输出将是一个方便的开始(你有多少GREF一次?),因为它也将帮助您确定正在创建哪些类型,以便您可以考虑减少它们的生命周期。

有关读取gref日志输出的指南也可能很方便。