Java类实例不会被销毁
我正在构建一个android应用程序,从硬编码的url获取数据 因为抓取可能需要一段时间,所以我首先编写了一个接口来支持回调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
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)
//回拨
而且它应该给你一种主要的安全感,即一旦需要内存,任务就会被收集起来
但是,我还希望消耗的/完成的/已经回调的实例离开,并离开堆,因为它们没有留下的意义
这真的不是由你来决定的。@ScaryWombatstatic
在这里是正确的。他想要一个全局变量来计算实例。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