Monodroid:执行完整GC
本文关键字:GC 执行 Monodroid | 更新日期: 2023-09-27 18:10:33
我试图创建我的小粒子系统。我有粒子管理器和粒子列表,并在画布上绘制我的粒子。我只在init((函数中创建过一次像Paint和etc这样的新对象!如果颗粒尺寸<0,我删除它:
for (int particle = 0; particle < particles.Count; particle++)
{
particles[particle].Update(); //particle size--;
if (!particles[particle].state) // size > 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(!!!(秒的暂停!!!我阅读了官方文件,但没有任何解决方案。我将我的代码与mono-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 < particles.Count; particle++) {
particles[particle].Update(); // position and size update
if (!particles[particle].state) // size > 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
GREF活动。
解决方案是而不是使Particle
成为Java.Lang.Object
的子类,并以任何方式更改您的体系结构以确保Particle
不是一个。
如果Particle
不是Java.Lang.Object
实例,那么我们缺乏足够的信息来重现问题并提出解决方案。GREF日志输出将是一个方便的开始(一次有多少GREF做?(,因为它还将帮助您确定正在创建哪些类型,以便您可以考虑缩短它们的使用寿命。
这个阅读gref日志输出的指南可能也很方便。