Monodroid:执行完整的GC [英] Monodroid: Performing a full GC

查看:96
本文介绍了Monodroid:执行完整的GC的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我尝试创建我的小粒子系统。我有粒子列表的ParticleManager并在画布上绘制我的粒子。我只是在init()函数中创建了任何像Paint等新对象!如果粒度< 0,我将它删除:

$ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $(for $(int particle = 0; particle< particles.Count; particle ++)
{
particles [particle] .Update(); //粒度 - ;
if(!particles [particle] .state)// size> 0? true:false
{
particles [particle] = null;
//在这里,我尝试了所有变化,如
//((IDisposable)particles [particle])。
//GC.SuppressFinalize (particles[particle]);
//System.GC.ReRegisterForFinalize(particles[particle]);
//((Java.Lang.Object)particles [particle])。Dispose();等等

particles.Remove(particles [particle]);
}

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

  GC清理摘要:测试1063个对象 - 复活1002. 
GC清理摘要:测试1053个对象 - 复活992.
...
GC清理摘要:1052个测试对象 - 复活988.
46800个未完成的GREF。执行完整的GC!

然后我的渲染线程中有10-15(!!!)秒的停顿!!!我阅读官方文件,但它没有任何解决方案。我分析和比较了我的代码与单一的JetBoy例子,但JetBoy的日志没有任何关于GC。尽管我用JetBoy的例子编写了我的程序。
如何解决完整的GC问题?


$ b编辑:
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);
}
尝试{
c = mSurfaceHolder.LockCanvas(null);

lock(mSurfaceHolder)
DoDrawRunning(c);
} finally {
if(c!= null)
mSurfaceHolder.UnlockCanvasAndPost(c);


$ b private void DoDrawRunning(Canvas canvas)
{
#region particles
for(int eng = 0; eng < engines.Count; eng ++)
{
engines [eng] .Update();
引擎[eng] .Draw(canvas);
}
#endregion
}

ParticleEnginee.cs p>

  public void Update(){
if(particles.Count< maxTotal){
for(int i = 0; i if(addNewB)
particles.Add(GenerateNewParticle()); //返回新的粒子
}
}

for(int particle = 0; particle< particles.Count; particle ++){
particles [particle] .Update (); //位置和大小更新
if(!particles [particle] .state)// size> 0?
particles.RemoveAt(particle);
}
}
public void Draw(Canvas canvas){
for(int j = 0; j <3; j ++)// 3粒子颜色级别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数量。



您可以通过 enable gref logging

  adb shell setprop debug.mono.log gref 

我假设 Particle 是一个 Java.Lang.Object 子类,这意味着您的至少 particles.Count GREF一次存活。



解决方案是 not make Particle a Java.Lang.Object 子类,并以任何方式修改您的体系结构以确保 Particle 不是一个。


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



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

I try to create my small particle system. I have ParticleManager with list of Particles and draw my particles on canvas. I create any new objects like Paint and etc once just in init() function! If particle size is < 0, I remove it:

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]);
        }

Then I create new Particle and add it to my list. What I see in my log:

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!

And then I have 10-15(!!!) second pause in my render thread!!! I read official documentation, but it hasn't any solution. I analysed and compared my code with mono JetBoy example, but JetBoy's log hasn't anything about GC. Although I wrote my program with JetBoy's example. How to fix full GC problem?


Edit: 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);
}

解决方案

The primary problem is that you have too many Java.Lang.Object instances alive at once, as each Java.Lang.Object instance contributes to the JNI global reference count, which also contributes to GC overhead. Want to reduce GC overhead? Reduce the number of GREFs you use.

You can track the GREF count by enabling gref logging

adb shell setprop debug.mono.log gref

I assume that Particle is a Java.Lang.Object subclass, meaning you have at least particles.Count GREFs alive at once.

The solution is to not make Particle a Java.Lang.Object subclass, and alter your architecture in any way to ensure that Particle isn't one.

If Particle isn't a Java.Lang.Object instance, then we lack sufficient information to reproduce the problem and suggest a solution. GREF logging output would be a handy start (how many GREFs do you have at once?), as it will also help you determine which types are being created so you can consider reducing their lifetime.

This guide on reading gref log output may also be handy.

这篇关于Monodroid:执行完整的GC的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆