Java Android线程分配-堆增长?

Java Android线程分配-堆增长?,java,android,multithreading,heap,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 savedInstan

大家好

在我使用需要重新启动的活动时,我正在开发一个针对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);
        }
    };
}
Thread t = new Thread(fullAnim);
t.start();
问题是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 loc,这是一个相当不错的解决方案,不会面临更大的影响。荣誉

我不使用计时器来安排任务-不知道这是否是一种不好的做法,但是 动画的名称如下所示:

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);
        }
    };
}
Thread t = new Thread(fullAnim);
t.start();

与任何JavaVM一样,堆内存将自动增长到最大大小。但是,位图是在虚拟机之外分配的,因此您不容易在统计信息中看到它们。最好的办法是确保不要使用大型位图,或者使用

当您在安卓1.6或更高版本上时,可以从Eclipse生成堆转储,并且可以使用EclipseMat分析转储

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

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

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

 android:largeHeap="true"
在舱单上。但这是非常不明智的,因为大多数应用程序不需要它。

因为最终变量对GC的优先级较低。因此,您需要在onPause方法中显式释放可运行对象,因为无法确保OnDestroy在完成调用后立即调用

@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);
运行的线程永远不会被垃圾收集。 如果活动停止或被破坏,线程不会自动停止。它可以永远运行。 每个非静态内部类都保留对封闭实例的引用。例如,手摇1;在该内部类中工作,因为它具有对AllocActivity.this的隐式引用。 因此,有效的做法是将活动的引用保持在比预期的活动时间更长的时间内,即直到onDestroy之后

如果您不再需要它们,请确保手动执行

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

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

参考此

或者
您可以在asynctask中执行操作,并使用onProgressUpdate在UI线程上发布进度,使用canceltrue与check in doInBackground结合使用是否已调用cancel来停止任务。

ya我了解到使用大型位图可能会导致分配问题,但即使我没有在线程/可运行项。。对于本例-fullAnim可能完全为空,但其中没有任何内容-堆仍将增长我尝试使用编写的示例活动-堆仍在增长:/您可以使用的另一种选择是计时器和TimerTask。您可以在销毁时取消计时器。