我在我的代码中收到警告:
这个AsyncTask类应该是静态的,否则可能会发生泄漏(匿名android.os.AsyncTask)
完整的警告是:
此AsyncTask类应该是静态的,否则可能会发生泄漏(匿名android.os.AsyncTask)静态字段将泄漏上下文.非静态内部类具有对其外部类的隐式引用.如果该外部类例如是片段或活动,则此引用意味着长时间运行的处理程序/加载器/任务将保留对活动的引用,从而阻止其收集垃圾.同样,对来自这些较长时间运行的实例的活动和片段的直接字段引用可能会导致泄漏.ViewModel类绝不应指向视图或非应用程序上下文.
这是我的代码:
new AsyncTask<Void,Void,Void>(){
@Override
protected Void doInBackground(Void... params) {
runOnUiThread(new Runnable() {
@Override
public void run() {
mAdapter.notifyDataSetChanged();
}
});
return null;
}
}.execute();
Run Code Online (Sandbox Code Playgroud)
我该如何纠正?
可能重复:是否
收集了Java Thread Garbage
考虑以下课程:
class Foo implements Runnable {
public Foo () {
Thread th = new Thread (this);
th.start();
}
public run() {
... // long task
}
}
Run Code Online (Sandbox Code Playgroud)
如果我们创建几个实例Foo做
new Foo();
new Foo();
new Foo();
new Foo();
Run Code Online (Sandbox Code Playgroud)
(请注意,我们没有指向它们的指针).
在线程结束之前,垃圾收集器是否可以删除这些实例run()?(换句话说:是否有Foo对象的引用?)
而且,另一方面,在`run()'中的线程结束后,或者我们是否在浪费内存("内存泄漏")后,GC会删除这些实例吗?
如果1.或2.是问题,那么正确的方法是什么?
谢谢
简而言之:我有一个完成运行的线程,但没有收集垃圾.
长:请参阅以下示例代码:
public void saveSomething() {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
// heavy memory access (~400 MB), finishes after ~10sec
}
});
thread.start();
}
Run Code Online (Sandbox Code Playgroud)
好的,所以这个线程在一段时间后开始并完成.在此期间使用了大量内存,这没关系.但我的问题是:
线程完成后,内存未设置为空闲
我不知道如何确保这一点.完成的线程,不再使用,应该收到垃圾收集,据我所知; 但这似乎不会发生在这里:(
从jvisualVM看这个截图:

1:我通过调用触发线程启动 saveSomething()
2:线程很久以前就已经完成了(我通过调试看到了它),我在jvisualvm中按下了"Perform GC"
正如你所看到的,在我强制GC之后,一切都按照我想要的方式工作.但这必须自动发生.我怎么能这样做,我做错了什么?
如果您需要更多信息,请询问.注意:似乎在一天(希望更短)后,内存恢复正常,GC可能只是"慢"或者不是经常定时?
线程是否会自动删除并在运行后收集垃圾,或者它是否继续存在并且即使在run()方法完成后也会占用内存?
例如:
Class A{
public void somemethod()
{
while(true)
new ThreadClass().start();
}
public class ThreadClass extends Thread{
public ThreadClass()
{}
@Override
public void run() {......}
}
}
Run Code Online (Sandbox Code Playgroud)
我想澄清一下这个线程是否会自动从内存中删除,还是需要明确地完成.
从Java API doc:
Java虚拟机继续执行线程,直到发生以下情况:
所有非守护程序线程的线程都已死亡,无论是通过从run方法调用返回还是抛出传播超出run方法的异常.
我希望我的假设是正确的,一旦线程完成其run()方法,它就有资格进行垃圾收集.在同样的背景下,我只是想知道:
run(),那么应该设置它的引用null吗?isAlive()或getState()在同一个线程对象上?无论是调用返回false和RUNNABLE
分别.我一直在我们的Android应用程序中注意到,每次我们退出到主屏幕时,我们都会通过ByteArrayOutputStream的数量增加堆大小(泄漏).我能够管理的最好的是添加
this.mByteArrayOutputStream = null;
Run Code Online (Sandbox Code Playgroud)
在run()结束时防止堆大小不断增加.如果有人能够启发我,我将非常感激.我写了下面的例子来说明问题.
public class MainActivity extends Activity {
private Controller mController;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.activity_main, menu);
return true;
}
@Override
protected void onStart() {
super.onStart();
this.mController = new Controller();
mController.connect();
}
@Override
protected void onStop() {
super.onStop();
mController.quit();
}
}
Run Code Online (Sandbox Code Playgroud)
public class Controller {
public volatile ReaderThread mThread;
public Controller() {
super();
}
public void connect() {
mThread = new ReaderThread("ReaderThread"); …Run Code Online (Sandbox Code Playgroud) 我创建了一个线程,该线程又创建了一个ThreadPoolExecutor并向其提交一些长时间运行的任务。在某些时候,原始线程由于未处理的异常/错误而死亡。执行器应该发生什么(它是该死线程的本地变量,没有对其的外部引用)?是否应该GCed?
编辑:这个问题从一开始就表述错误,但我将其保留,因为 Gray 提供了一些有关 TPE 如何工作的详细信息。
onReceive方法中的线程在完成之前是否有资格进行垃圾回收?
@Override
public void onReceive(final Context context, Intent intent) {
final int alarmId = intent.getExtras().getInt(EXTRA_ALARM_ID);
Log.i(TAG, "/onReceive with an alarmVo.id of " + alarmId);
// RUN MY THREAD
new Thread(new Runnable() {
@Override
public void run() {
AlarmUtil.setNextAlarm(context, alarmId);
}
}).start();
}
Run Code Online (Sandbox Code Playgroud)
从我在这里的理解:http: //developer.android.com/reference/android/content/BroadcastReceiver.html它是,但我不太确定.
"任何需要异步操作的东西都不可用,因为您需要从函数返回来处理异步操作,但此时BroadcastReceiver不再处于活动状态,因此系统可以在异步操作完成之前自由终止其进程."
如果它被垃圾收集,那么我该如何解决这个问题呢?我的方法应该是什么?
当线程中的run()方法完成或者调用它的函数完成时收集线程垃圾?
我没有问题或任何事情,但我想避免内存泄漏等.
对于喜欢代码的人:
public void SomeClass {
public SomeClass() {
}
public void someMethod() {
Object data = veryBigObject;
while(true) {
MyThread thread = new MyThread(veryBigObject);
thread.run();
try {
Thread.sleep(1000);
} catch (InterruptedException e) { /* do nothing */ }
}
}
public static void main(String[] args) {
SomeClass myclass = SomeClass();
myclass.someMethod();
}
}
public class MyThread extends Thread {
private Object data;
public Thread(Object data) {
this.data = data;
}
public void run() {
// do …Run Code Online (Sandbox Code Playgroud) 我是这样开始我的线程的:
(new MyThread()).start();
Run Code Online (Sandbox Code Playgroud)
我没有在任何地方保留它的引用,所以我想知道它是否是一种安全的方法 - 不能GC收集它,因为它没有被引用?
如果不是(我想是的),为什么呢?