Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/401.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/187.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java类实例不会被销毁_Java_Android_Callback_Garbage Collection - Fatal编程技术网

Java类实例不会被销毁

Java类实例不会被销毁,java,android,callback,garbage-collection,Java,Android,Callback,Garbage Collection,我正在构建一个android应用程序,从硬编码的url获取数据 因为抓取可能需要一段时间,所以我首先编写了一个接口来支持回调 public interface MyCallBack { void data_received(String data); } 在主活动中,我实现了MyCallBack public class MainActivity extends AppCompatActivity implments MyCallBack { @Override public

我正在构建一个android应用程序,从硬编码的url获取数据

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

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
   }
}
公共类BackgroundWorker扩展异步任务{
MyCallBack caller;//数据到达时要回调的对象
私有静态int实例\u counter=0;//计数bw实例
后台工作人员(MyCallBack cb){
呼叫方=cb;
实例_计数器++;
Log.d(“新创建的bw对象”,“当前计数:+实例\计数器”);
}
@重写受保护的void finalize()可丢弃{
实例_计数器--;
Log.d(“bw对象已销毁”,“剩余计数:”+实例\计数器);
}
@重写字符串doInBackground(…){…}//满足AsynTask
//并执行实际的URL post/get操作,然后转发输出
//对onPostExecute()方法
@重写void onPostExecute(字符串s){
//我可以先检查呼叫者是否为空,但你知道了。
调用者。收到的数据;
caller=null;//只是为了使此实例没有指向活动的指针
}
}
现在,当我多次单击按钮时,我可以看到一个接一个地创建对象。每次在我的活动中我都会得到数据

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

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


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

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


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

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


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

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


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

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

但它们从未被销毁。我担心我在某处发生内存泄漏,我的应用程序会在某一点上崩溃,因为我的内存管理不善


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

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

唯一可能引起怀疑的是,您的
AsyncTask
实例不仅对任何回调都有很强的引用,而且对整个
活动也有很强的引用

尽管如此,
垃圾收集器
在处理循环引用方面还是经过了良好的训练,但我承认我不知道它是否会等到
活动
被gc'完成后再收集
异步任务
,或者它会尽快完成

在任何情况下,您都可以将
回调
引用封装在
WeakReference

private WeakReference caller;//数据到达时要回调的对象
// ...
调用方=新的WeakReference(cb);
// ...
if(caller.get()!=null)
//回拨
而且它应该给你一种主要的安全感,即一旦需要内存,任务就会被收集起来

但是,我还希望消耗的/完成的/已经回调的实例离开,并离开堆,因为它们没有留下的意义


这真的不是由你来决定的。

@ScaryWombat
static
在这里是正确的。他想要一个全局变量来计算实例。OP实例没有被销毁-你怎么知道?@ScaryWombat因为
finalize()中的
Log.d
永远不会被调用。你确定发生了
gc
吗?没有任何地方可以很快调用finalize。你是否使用适当的工具分析了你的应用程序?我测试了一个与你类似的代码,并且在达到300计数后收集了实例(pc,不是移动的,但仍然…).你不应该根据输出日志做任何假设。。。
private WeakReference<MyCallBack> caller;   // object to be called back when data arrives
// ...
caller = new WeakReference<>(cb);
// ...
if (caller.get() != null)
     // call callback