Java类实例不会被销毁

时间:2018-03-28 07:32:03

标签: java android callback garbage-collection

我正在构建一个从硬编码网址中获取数据的Android应用程序。

因为提取可能需要一段时间,所以我首先编写了一个支持回调的接口

public interface MyCallBack {
   void data_received(String data);
}

在主要活动中,我实施了MyCallBack

public class MainActivity extends AppCompatActivity implments MyCallBack {

  @Override
  public void data_received(String data) {
    Log.d("got data", data);
    // do something useful with data...
  }

  public void btn_getData_clicked(View view) {
       // a button is clicked, and fetching is started:
       BackgroundWorker bw = new BackgroundWorker(this);
       bw.execute("https://randomuser.me/api/");

      // after this point, bw does not leave the heap, 
     //  because BackgroundWorker keeps a reference to (this)
  }
}

我想让我的代码在按下按钮时单独获取。 但是我也希望消耗/完成/已经调用的返回实例消失,然后离开堆,因为它们没有任何意义。

因此,在BackgroundWorker类中,我在调用接口方法后立即将调用者设置为null:

public class BackgroundWorker extends AsyncTask<String,Void,String> {

    MyCallBack caller;   // object to be called back when data arrives

    private static int instances_counter = 0;   // counts bw instances

    BackgroundWorker(MyCallBack cb) {
      caller = cb;
      instances_counter ++;
      Log.d("new bw object created", "current count: " + instances_counter );
    }

   @Override protected void finalize() throws Throwable {
      instances_counter --;
      Log.d("bw object destroyed","remaining count: " + instances_counter );
   }

   @Override String doInBackground(...) {...} // satisfy AsynTask 
   // and do the actual URL post/get stuff then forward the output
    // to onPostExecute() method


   @Override void onPostExecute(String s) {
      // I can check if caller is null first, but you get the idea.
      caller.data_received(s);

      caller = null;   // just so that this instance has no pointer to activity
   }
}

现在,当我多次单击该按钮时,我可以逐个看到创建的对象。我每次都在活动中获取数据。

  

创建了D / new bw对象:当前计数:1

     

获得数据:{“结果”:[{“性别”:“女性”......

  

创建了新的bw对象:当前计数:2

     

获得数据:{“结果”:[{“性别”:“男性”......

  

创建了D / new bw对象:当前计数:3

     

获得数据:{“结果”:[{“性别”:“女性”......

  

创建了D / new bw对象:当前计数:4

     

获得数据:{“结果”:[{“性别”:“女性”......

  

创建了D / new bw对象:当前计数:5

     

获得数据:{“结果”:[{“性别”:“男性”......

但他们永远不会被摧毁。我担心我在某个地方发生了内存泄漏,而且我的应用程序因为我的内存管理不善而一度崩溃。

为什么这些实例没有被销毁?

1 个答案:

答案 0 :(得分:1)

finalize方法中的日志输出不是确定对象是否导致内存泄漏的正确方法。

可能引发疑虑的唯一部分是,您的AsyncTask个实例不仅对任何回调都有强烈的参考,而且对您的整个Activity都有强烈的参考。

仍然,Garbage Collector 训练有素无论如何都要处理循环引用,但我承认我不知道它是否会等到Activity是gc'ed收集AsyncTask也是如此,或者它会尽快收集。

在任何情况下,您都可以将Callback引用包含在WeakReference<T>

private WeakReference<MyCallBack> caller;   // object to be called back when data arrives
// ...
caller = new WeakReference<>(cb);
// ...
if (caller.get() != null)
     // call callback

它应该给你一个重要的安全感,一旦需要内存就会收集任务。

  

但是我也希望消耗/完成/已经调用的后台实例消失,然后离开堆,因为它们没有任何意义。

老实说,这不是由你来决定的。