【问题标题】:How to remove object/instance from memory after removing it from map?从地图中删除对象/实例后如何从内存中删除它?
【发布时间】:2015-07-01 12:15:00
【问题描述】:

我在公开可用的地图中保留对本地创建的对象的引用。当我从地图中删除对象时,它也应该从内存中删除(无效)。

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");
      }
 }

在上面的代码中,“Still exists”是myMap.remove("Key")之后的打印结束。这意味着该对象仍然存在于内存中。如何从内存中删除它?

【问题讨论】:

  • Runnable 不在乎它是否在地图中。
  • 我认为 runnable 不是问题,因为我在从地图中删除对象之前将 inifiniteloop 设置为 false。
  • 不,您将其设置为 false Thread 已经运行之后。你可以简单地用调试器检查它。
  • 请注意我的回答,你犯了这么多错误,比如无限循环应该是布尔无限循环,Runnable 应该已经实现了 run 方法等。我的简单问题在这里你是如何测试上述程序的???跨度>
  • @Dev 感谢您改进代码,我将其添加到我的问题中。我没有测试我的代码。这是用来澄清我的问题的伪代码。它实际上不必工作。

标签: java android object memory dictionary


【解决方案1】:

Java 会在最适合您的时候从内存中删除对象,所以不用担心。如果您真的想确保线程被终止,您应该保留对您的Thread 和/或Runnable 的引用,以便您可以尝试优雅地关闭线程(必要时突然关闭)。

如果您想尽快将对象从内存中删除,您可以尝试 System.gc() 您可以尝试 System.gc() 但这被认为是 bad practice

使用涉及的父实例变量可能涉及一些技巧,导致线程不会终止,但比我更聪明的人肯定可以解释:)

【讨论】:

  • 我认为线程不是问题,因为当我将 inifiniteloop 设置为 false 时,线程在完成后会终止。但是对象 x 仍然存在于内存中。
  • X 类代表蓝牙信标。我的(Android)应用程序为范围内的每个信标创建一个对象,并保留对地图中所有信标对象的引用。当信标不再在范围内时,我想将其从地图和内存中完全删除,以避免在内存中存在大量不在范围内的信标对象。这积累得非常快。所以从内存中删除对象很重要。 gc 需要多长时间才能确定不再需要该对象并将其删除?
  • 这真的超出了解释GC工作的评论范围,我只能参考[Oracle文档](www.oracle.com/webfolder/technetwork/tutorials/obe /java/gc01/index.html)。您可能不得不过度考虑如何存储对象。不幸的是,我不是 Android Pro。
  • 考虑将“android”添加到您的标签或使用 android 标签和您的用例重新提交您的问题以获得更多有用的答案:)
  • @MeesterPatat @wonderb0lt 伙计们,我很抱歉,但是如果这个答案是错误的,怎么能被接受呢? 1) 作者的问题显然在于不正确的同步(即根本没有同步) 2) 你不能通过引用Runnable 来停止线程 3) 你永远不应该 通过Thread.stop 停止线程 4) 你不能通过Thread.interrupt() 停止这个线程,因为代码不检查中断标志 5) 你不能保证 GC via System.gc() 因为它只是 建议 JVM 运行 GC。
【解决方案2】:

您正在使用remove 仅从地图中删除您的对象,但该对象仍然存在。如果没有对它的引用,JVM 将自动收集您的对象。您需要设置 x=null 以使 X 对象符合 GC 条件。 这将删除对您的对象的引用。

另外,请记住,GC 过程不是立即的。它不是确定性的。它在 JVM 中的一个单独线程上运行。

设置 x=null 会从原始对象中删除引用。然后该对象有资格进行 GC。此外,该对象已从地图中移除,因此地图中对该对象的任何引用也不存在。

如果您的对象没有得到 GC,请确保在其余代码中没有对该对象的引用。您只提供了伪代码,我认为您可能应该更广泛地搜索您的问题

【讨论】:

  • 但是如何从地图中将 x 设置为 null?我不想在地图之外保留对 X 类的引用,因为一次有多个 x 实例。当我从地图中删除对象时,我不再需要它并想将其从内存中删除。
  • 我建议并被否决了,我也 100% 确定如果其他繁忙的线程具有更高的优先级,它不会被收集和泄漏...
  • 不会从 map 中获取值只是复制对象吗?
  • @MeesterPatat Java != C。如果您想要确定性内存管理,请使用 C
【解决方案3】:

正在运行的线程没有看到infiniteloop 变量已更改。 要使此更改可见,您需要添加一些同步。例如,将此变量标记为volatile

public volatile boolean infiniteloop = true;

现在应该可以了。无需再做任何事情,无需 x=null 之类的。 要了解更多信息,请阅读Java Memory Model

【讨论】:

  • 因此,如果我使 inifiniteloop volatile 并将其设置为 false,则线程将终止,如果我从映射中删除对象 x,它会立即自动从内存中删除,因为在我的申请?
  • @MeesterPatat 没错,除了一件事:没有保证它会立即被删除,但它肯定会符合进一步GC。
  • 有什么办法可以立即删除吗? Wonderb0lt 建议使用 System.gc() 但这是一个不好的做法。
  • @MeesterPatat 不,没有这样的方法。你是对的,System.gc() 是一种不好的做法,而且,JVM 运行 GC 只是 建议,所以再一次,不保证它会实际运行。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-11-21
  • 1970-01-01
  • 2020-10-26
  • 2015-05-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多