Timer threads and presenter questions


#1

Hello,

I have two questions, one that is specific for one of the projects that I work on and the other is general.

  1. I have a method in one of my apps that updates a field pertaining to a location to a location passed to that method. Here’s how the method looks like:

    /**

    • Last location stored in this class will be updated by the latest location. It is in timer because
    • last location can be used on several places in the project. If we immediatly update lastLocation
    • object then on ui (map) changes will not be reflect
    • So it should be after a few seconds.
    • @param location latest location
      */
      private void updateLastLocation(final Location location) {
      new Timer().schedule(new TimerTask() {
      @Override
      public void run() {
      lastLocation = location;
      }
      }, 3000);
      }

Ignoring the typos (it’s from India), this block of code causes the device to run out of memory. More specifically:> Fatal Exception: java.lang.OutOfMemoryError

pthread_create (1040KB stack) failed: Try again

Basically, it creates all those threads every 3 seconds that apparently never end. My question is - why are these threads not closed immediately after they finish the code in their run method? I tried reading in the docs but it doesn’t really specify. I tried putting a cancel(); method at the end of the block and some of them seem to be garbage collected after a while but still, many more are created than are garbage collected. I’ve also tried using executors, like this:

//create a new single thread executor if it's null and name its thread "updateLastLocation"
    if (executor == null) executor = Executors.newSingleThreadScheduledExecutor(r -> new Thread(r, "updateLastLocation"));
    //execute this runnable every 3 seconds
    executor.schedule(() -> {
        lastLocation = location;
    }, 3, TimeUnit.SECONDS);

I have currently decided to get rid of this threading altogether and simply update that variable in the current thread, without any delay. But assuming I want to keep this “refresh every 3 seconds” behavior, how do I determine the threads to be closed “immediately” after they finish so that I get rid of the out of memory error?

  1. The second question is related to the MVP pattern. Let’s suppose I declare a Contract interface that has a View interface (implemented by the Activity) and the Presenter interface (implemented by the presenter). Since I am creating a new presenter in the activity and passing a reference to the activity as the View interface, then the presenter has a reference to the activity. And the activity also has a reference to the presenter. Isn’t that a circular reference that prevents both object from being garbage collected in the case of an orientation change, for example? Should I be assigning the presenter to null in the activity’s onDestroy(), so that the presenter is garbage collected and the activity can also be garbage collected, not having any object (the presenter) referencing it anymore?

I’ve worked with MVP apps before but I don’t remember seeing this kind of approach.

Thanks!


#2

I have no idea, sorry. I almost never use Timer and TimerTask. I would have the same expectations as you do with regards to how that code would work.

The single-thread ScheduledExectorService should only have a single thread. If there is a likely opportunity to do so, you can call shutdown() or shutdownNow() on the ScheduledExectorService to try to get rid of that one thread.

However, I would ensure that you only have one ScheduledExecutorService, not N of them. You have a bit of a race condition in your current create-the-executor code, if it might be called on multiple threads (not sure where this code is being used). I’d just make it as a final field on whatever it is that houses this code and initialize it up front.

No, unless something from outside the circular reference refers to something in the circular reference itself.

While your activity is in the foreground, the framework has a reference to the activity, so the activity and the rest of the circular reference cannot be garbage collected. When that activity gets destroyed, the framework reference to it should go away. At that point, assuming there are no other external references (e.g., you stuck a View in a static field, you forked a thread that keeps running and has a reference), the whole circular reference will be eligible for garbage collection. It make take longer for that GC to occur, depending on how the GC algorithm is tuned with respect to dealing with complex circular graphs.

If it makes you feel better and won’t break anything, sure. If the presenter is being retained across configuration changes, you would need to update the presenter to point to the new activity reference anyway. However, just because A refers to B and B refers to A does not mean that the A+B object graph can never be garbage collected.


#3

Thanks. Speaking of static View variables, why are they so terrible in terms of creating memory leaks? I mean, I know a static variable belongs to the actual class and not to an instance of that particular class, but why is that so terrible? If my activity has a static reference to a TextView, for example, why can’t it be garbage collected? It’s a bit weird because it’s a static variable that should belong to a class but it’s in an actual object - but truthfully, I can’t exactly think what that actually means.


#4

Anything that is referenced via a static field cannot be garbage collected. A View has a reference to its hosting Activity. So, if a static field has a reference to a View, it prevents the View, the Activity, and anything else in that object graph from being garbage collected.

In effect, static is Java’s way of implementing global variables, just with a light namespace implementation (the field is associated with a class).


#5

I see. So basically, once a static variable has been initialized, it cannot be garbage collected, no matter what.

When is a static variable garbage collected, by the way? Whenever the process ends or something? How’s its lifetime determined?

Even if it is declared in an activity that can be garbage collected, that is irrelevant since it doesn’t really “belong” to that activity, anyway. As far as the JVM is concerned, it’s a static variable that has a reference to a View, and the View has a reference to the Activity, and none of these are GCed?

Interesting. So it’s similar to my example with the presenter and view, except in this case the “cyclic dependency” really creates a problem, whereas in the presenter and view example that’s not the case because none of the references are static.

Are these problems exactly the same in Kotlin? I would assume so, if you use @JvmStatic or something for a reference to a View.


#6

Never. It goes away when the process does.

Correct.

In general, yes. Kotlin does not directly have static, but it has its own global non-collectable objects.


#7

Great, thank you for the answer. I will continue to read the books :slight_smile: to find more.