Ant4res
Ant4res

Reputation: 1225

How garbage collector release AsyncTask allocated memory

In the MainActivity, every x seconds I create a new AsyncTask and I call execute with new RTask(this).execute(param); to send data to a server asyncronously. I think that create a new task so often can cause memory leaks. So when garbage collector release the memory and how can I set the task reference to null to allow to collect it? I've tried to use this.cancel(true); within onPostExecute() but I've read that, due to a bug of the Android framework, onpost is never called. Any suggestion will be greatly appreciated.

Thanks

Upvotes: 1

Views: 3949

Answers (2)

Deepak Bala
Deepak Bala

Reputation: 11185

How garbage collector release AsyncTask allocated memory

Like it releases memory for any other class. There is nothing special about an AsyncTask. Once the task is done it will be garbage collected as long as no other class refers to it. Setting the task reference to null will help.

Upvotes: 1

sandrstar
sandrstar

Reputation: 12643

Actually, there shouldn't be any issue with AsyncTask recycling unless You hold any reference to it from param or generate memory leaks inside doInBackground().

So, You might think, that if You're creating many long-running AsyncTasks then it would lead to some memory issues. Actually it's not true (at least on latest Android versions). AsyncTask source code shows that

  • It uses singleton bounded executor:

    private static final int CORE_POOL_SIZE = 5;
    private static final int MAXIMUM_POOL_SIZE = 128;
    private static final int KEEP_ALIVE = 1;
    
    public static final Executor THREAD_POOL_EXECUTOR
        = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
                TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);
    

    That means that executor won't run more than 128 AsyncTasks the same time (128 is not very big per my understanding).

  • It uses bounded query for the Executor:

    private static final BlockingQueue<Runnable> sPoolWorkQueue =
            new LinkedBlockingQueue<Runnable>(10);
    

So, based on the above points, number of created and running the same time AsyncTasks are limited and not so big. So, if Your code inside AsyncTask doesn't create any memory leaks, then per my understanding there's no issue. Same time Android won't let You spam itself with AsyncTasks. Checkout ThreadPoolExecutors description to get familiar with the way it manages a memory (If You worry about too many created threads the same time).

Especially in Your case, I don't think that it's a good idea to execute another request to the server while previous one is not finished yet (in case of similar requests), also there's no point to execute many frequent small requests - Your app will draw battery too fast in this case.

Regarding cancel() call, based on Android documentation for AsyncTask:

Cancelling a task

A task can be cancelled at any time by invoking cancel(boolean). Invoking this method will cause subsequent calls to isCancelled() to return true. After invoking this method, onCancelled(Object), instead of onPostExecute(Object) will be invoked after doInBackground(Object[]) returns. To ensure that a task is cancelled as quickly as possible, you should always check the return value of isCancelled() periodically from doInBackground(Object[]), if possible (inside a loop for instance.)

So, I'm not sure that You've meant by "I've tried to use this.cancel(true); within onPostExecute()" while cancel() has nothing to do if called from onPostExecute(). It can be called out from AsyncTask or from doInBackground() and it's a good practice to call isCancelled() if You have a loop in AsyncTask in order to stop its execution once cancel() called.

Upvotes: 5

Related Questions