Android线程分配 - 增长堆?

时间:2013-08-24 07:02:04

标签: java android multithreading heap

大家好,

我正在开发一个针对API 7的Android应用程序,此时我正在使用需要重新启动的活动。让我们说我的活动看起来像这样:

public class AllocActivity extends Activity implements OnClickListener{

    Button but;
    private Handler hand = new Handler();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        setContentView(R.layout.activity_alloc);

        but = (Button) findViewById(R.id.button);
        but.setText("RELOAD");
        but.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View arg0){
                Intent intent = getIntent();
                startActivity(intent);
                finish();
            }
        });  
    }

    @Override
    protected void onDestroy(){
        super.onDestroy();
        System.gc();
    }

    /****** THREADS AND RUNNABLES ******/

    final Runnable fullAnim = new Thread(new Runnable(){
        @Override
        public void run(){
            try{
                hand.post(anim1);
                Thread.sleep(2000);
                hand.post(anim2);
                Thread.sleep(1000);
                // and so on
            }catch(InterruptedException ie){ie.printStackTrace();}
        }
    });

    final Runnable anim1 = new Runnable() {
        @Override
        public void run(){
            // non-static method findViewById
            ImageView sky = (ImageView)findViewById(R.id.sky);
        }
    };
}

问题是gc似乎没有释放fullAnim线程,因此每次重启时堆都会增长~100K - 直到它减速并崩溃。将fullAnim声明为静态确实解决了这个问题 - 但是因为我使用非静态引用,这对我来说不起作用。

所以在这一点上我很失落 - 我希望你能告诉我下一步该去哪儿。有什么我可能做错了或者是否有一个工具可以用来管理线程在重启后丢弃并释放堆。

亲切地问候

更新

感谢所有回答的人 - 帮助了很多。使用TimerTask最终做到了这一点。我做了以下改动:

/****** THREADS AND RUNNABLES ******/

final TimerTask fullAnim = new TimerTask(){
    @Override
    public void run(){
        try{
            hand.post(anim1);
            Thread.sleep(2000);
            hand.post(anim2);
            Thread.sleep(1000);
            // and so on
        }catch(InterruptedException ie){ie.printStackTrace();}
    }
};

由于活动长度超过6k,这是一个相当不错的解决方案,没有面临更大的影响。 KUDOS!

我不使用计时器来完成任务 - 不知道它的不良做法但是 动画的调用方式如下:

Thread t = new Thread(fullAnim);
t.start();

4 个答案:

答案 0 :(得分:3)

  • 永远不会收集正在运行的Thread
  • 如果Activity停止或被销毁,则线程不会自动停止。它可以永远运行。
  • 每个非静态内部类都保持对封闭实例的引用。例如。 hand.post(anim1);在内部类中工作,因为它具有对AllocActivity.this的隐式引用。

所以你实际做的是保持对Activity活着的引用的时间超过它应该存活的时间,即直到onDestroy之后。

如果您不再需要,请务必手动stop threads

答案 1 :(得分:2)

与任何Java VM一样,堆内存将自动增长到最大大小。但是,位图在VM外部分配,因此您不会在统计信息中轻松“看到”它们。您可以做的最好的事情是确保您不使用大位图,或使用它们缩小它们 http://developer.android.com/reference/android/graphics/BitmapFactory.Options.html

从Eclipse开始,您可以在Android 1.6或更高版本上生成堆转储,并且可以使用Eclipse MAT分析转储。

通常,您无法控制真实设备上的最大堆大小,除非您使用自定义硬件或固件。

在developer.android.com上应该有一篇关于在1.6上转储堆的文章,但是我找不到它。 :(

编辑 另外,我必须提到您可以使用

为应用程序请求更多内存
 android:largeHeap="true"
清单中的

。但由于大多数应用程序不需要这样做,因此这是非常不适合的。

答案 2 :(得分:1)

因为最终变量的GC优先级较低。所以你需要在onPause()方法中显式释放runneable对象,因为没有完成onDestory()会在finish()调用后立即调用。

@Override
    protected void onPause(){
        super.onPause();
        //cancel timer to stop animations
       if(t!=null){
        t.cancel();
       }

        System.gc();
    }

<强>更新

使用计时器来实现这个目标

boolean isFirstAnim=true;
Timer t = new Timer();
        t.schedule(new TimerTask() {

            @Override
            public void run() {
                          if(isFirstAnim){
                              // play your first animation at every
                          }else{
                              // play your second animation at every
                          }                 
            }
        }, 0, 3000);

答案 3 :(得分:1)

What happens when all activities of an application finishes?

  

“当你调用finish()时,这并不意味着Activity实例   垃圾收集。你告诉Android你要关闭   活动(不再显示)。它将一直存在,直到   Android决定终止进程(从而终止DVM)或   该实例被垃圾收集。“

你需要实现自己的stop方法来停止正在运行的线程,你可以在onDestroy中调用它

参考此Stopping a runnable

可替换地 你可以在asynctask中执行你的操作,并使用onProgressUpdate()在UI线程上发布进度,并使用cancel(true)和check in doBackground()来检查是否已经调用cancel来停止任务。