1

I am keeping a reference to locally created objects in a publicly available map. When i remove the object from map, it should also be removed from memory(nullified).

public class X {
    public boolean infiniteloop = true;

    public X() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                while (infiniteloop) {
                    System.out.println("Still exists");
                }
            }
        }).start();
    }


public class Y{
      Map myMap = new HashMap();
      public Y() throws InterruptedException{
       X x = new X();
       myMap.put("Key", x);
       Thread.sleep(10000);
       ((X)myMap.get("Key")).infiniteloop= false;
       myMap.remove("Key");
      }
 }

In the above code, "Still exists" is printend after myMap.remove("Key"). This means the object still exists in memory. How can i remove it from memory?

MeesterPatat
  • 2,671
  • 9
  • 31
  • 54
  • The `Runnable` does not care if its in a map or not. – Murat Karagöz Apr 23 '15 at 11:00
  • 1
    The runnable isn't the problem i think, because I set inifiniteloop to false before removing the object from map. – MeesterPatat Apr 23 '15 at 11:04
  • No, you set it to false _after_ the `Thread` is already running. You can simply check it with a debugger. – Murat Karagöz Apr 23 '15 at 11:05
  • Please observe my answer ,you are making so many mistakes ,like infiniteloop should be boolean infiniteloop ,Runnable should have run method implemented etc. My simple question here how you have tested above program??? – Dev Apr 23 '15 at 11:25
  • @Dev thank you for the improved code, I added it to my question. I didn't test my code. It was pseude code to clarify my question. It didn't really have to work. – MeesterPatat Apr 23 '15 at 11:33

3 Answers3

2

Java takes care of removing objects from memory at the optimal moment for you, so don't worry about that. If you really want to make sure the thread is terminated you should keep a reference to your Thread and or Runnable so you can try to shut down the Thread gracefully (and abruptly if necessary).

If you want to try to get the object removed from memory ASAP you could try System.gc() You could try System.gc() but that is considered bad practice

There's probably some trickery involved in using a parent instance variable involved that makes the thread not terminate, but someone smarter than me can surely explain that :)

Community
  • 1
  • 1
wonderb0lt
  • 2,035
  • 1
  • 23
  • 37
  • I don't think the thread is the problem because when i set inifiniteloop to false the thread gets terminated after it's done. But the object x still exists in memory. – MeesterPatat Apr 23 '15 at 11:08
  • The X class represents a bluetooth beacon. My (Android)app makes an object for every beacon in range and keeps a reference to all the beacon objects in a map. When the beacon is not in range anymore, I want to remove it completely from map and memory to avoid having a lot of beacon objects in memory while they're not in range. This accumulates very fast. So it's important to remove the objects from memory. How long does it take the gc to determine that the object is not needed anymore and to remove it? – MeesterPatat Apr 23 '15 at 11:19
  • This really is beyond the scope of a comment to explain the workings of a GC, I can only refer you to the [Oracle Documentation](www.oracle.com/webfolder/technetwork/tutorials/obe/java/gc01/index.html). You may have to overthink how you store objects. I'm not an Android Pro unfortunately. – wonderb0lt Apr 23 '15 at 11:32
  • Consider adding "android" to your tags or resubmit your question with an android tag and your use-case to get more helpful answers :) – wonderb0lt Apr 23 '15 at 11:33
  • @MeesterPatat @wonderb0lt Guys, I'm sorry, but how can this answer be accepted when it is wrong? 1) The author's problem is obviously in improper synchronization (i.e. there is no synchronization at all) 2) You _can not_ stop thread via reference to `Runnable` 3) You _should never, ever_ stop thread via `Thread.stop` 4) You _can not_ stop this thread via `Thread.interrupt()` because the code doesn't check interruption flag 5) You _can not_ have _garanteed_ GC via `System.gc()` because it is just _suggestion_ for JVM to run GC. – AlexW Apr 23 '15 at 11:50
  • (1) It's not, read all comments. (2) Agreed, but he could've set a "stop" flag on it. However, (3/4) using Thead.interrupt() would be the better way (I never advised to use either `Thread.stop` or `Thread.interrupt()`). As for (5), I've linked him to a thread that explains why it's a bad idea. They should re-ask the question more clearly / with proper tags. – wonderb0lt Apr 23 '15 at 11:58
2

You are removing your object only from the Map using remove, but the object still exists. JVM will Garbage Collect your object automatically if there are no references to it. You would need to set x=null to make the X object eligible for GC. This removes the reference to your object.

Also, bear in mind that the GC process is not immediate. It is not deterministic. It runs on a separate thread in the JVM.

Setting x=null removes the reference from the original object. Then that object is eligible for GC. Also, the object has been removed from the map, so any references to the object within the map are also not there.

If your object is not getting GC'ed, make sure that there are no references to the object in the rest of the code. You provided only pseudo-code, and I think you should probably search wider for your problem

CocoNess
  • 4,213
  • 4
  • 26
  • 43
  • But how do i set x to null from the map? I don't want to keep reference to class X outside the map because there are multiple instances of x at one time. When i remove the object from the map, i don't need it anymore and want to remove it from memory. – MeesterPatat Apr 23 '15 at 11:07
  • i suggested that and got downvoted to oblivion, also i'm 100% sure it will not get collected and leak if some other busy thread has higher priority... – Palcente Apr 23 '15 at 11:08
  • Wouldn't getting the value from map just make a copy of the object? – MeesterPatat Apr 23 '15 at 11:28
  • @MeesterPatat Java != C. If you want deterministic memory management use C – CocoNess Apr 23 '15 at 11:38
1

The running thread does not see that infiniteloop variable has been changed. To make this change visible, you need to add some synchronization. E.g., mark this variable as volatile:

public volatile boolean infiniteloop = true;

Now it should work. No need to do anything more, no x=null and stuff. To know more, read about Java Memory Model.

AlexW
  • 896
  • 7
  • 9
  • So if I make inifiniteloop volatile and set it to false the thread gets terminated and if i remove the object x from the map, it immediately automatically gets removed from memory because there is no reference to it in my application? – MeesterPatat Apr 23 '15 at 11:12
  • @MeesterPatat That's correct, except one thing: there is no garantee that it will be removed _immediately_, but it definitely will be _eligible_ for further GC. – AlexW Apr 23 '15 at 11:16
  • Isn't there any way to remove it immediately? Wonderb0lt suggested System.gc() but that's a bad practice. – MeesterPatat Apr 23 '15 at 11:26
  • @MeesterPatat No, there is not such way. You are right, `System.gc()` is a bad practice, and moreover, it is just _suggestion_ for JVM to run GC, so again, no garantee it will be actually run. – AlexW Apr 23 '15 at 11:35