释放分配给Java中对象的内存

时间:2014-09-20 09:33:14

标签: java c++

在C ++中,您可以释放分配给对象的内存,如下所示:

int main(){
    string myString("MyString");
    string *stringPointer = &myString;
    cout<<myString<<" "<<*stringPointer;
    delete stringPointer;
    cout<<myString; //crash
    return 0;
}

在二叉搜索树(或任何其他情况)中,当您需要删除节点时,可以使其符合Java中的垃圾收集条件。但你不能这样做

Node nodeToDelete = getNodeToDelete();
nodeToDelete = null;  //the original reference is still there in the tree

这就像在C ++中将指针变量设置为NULL

pointerVariable = NULL;

要使BST删除功能在Java中工作,我们需要转到节点的父节点并将子节点设置为删除为null。 是否有像C ++中的delete这样的Java语言功能,以使事情变得更容易?

2 个答案:

答案 0 :(得分:1)

不,Java中没有语言功能允许您提前有选择地删除特定对象(如Python中的del)。你需要相信垃圾收集器会完成它的工作。 (通常情况下,这样做非常好。)

Java的垃圾收集器基于对象可达性(不是像CPython中的引用计数,而不是像Boehm GC中那样的内存扫描)。这样,任何没有实时引用的对象都会被垃圾回收。参考可以是间接的,但死物和死循环的参考不会刺激车库收集器。

一些例子:

class Dummy {
    String name;
    Dummy other;
    Dummy(String name) { this.name = name; }
}

void f1() {
    Dummy peter = new Dummy("Peter");
    peter.other = new Dummy("Fred");
    peter.other.other = new Dummy("Megan");
    // None of the objects is eligible for garbage collection since
    // "Peter" is live and "Fred" can be reached via "Peter" (therefore
    // "Fred" is alive) and "Megan" can be reached via "Fred".
    peter.other = null;
    // Now the reference to "Fred" is lost which makes him a candidate
    // for garbage collection.  "Megan" is dead too because the
    // reference from the dead object "Fred" does not count.
    // As the method returns, all three objects are dead and can be
    // collected.
}

void f2() {
    Dummy clementine = new Dummy("Clementine");
    clementine.other = new Dummy("Charles");
    clementine.other.other = new Dummy("Caroline");
    clementine.other.other.other = clementine;
    // Here we have a cycle of
    //
    // +--> "Clementine" --> "Charles" --> "Caroline" --+
    // |                                                |
    // +------------------------------------------------+
    //
    // and since "Clementine" is live, all three are.
    clementine = null;
    // Once we loose the reference to "Clementine", the cycle still
    // exists (every object is referenced by at least one other object)
    // but the cycle is dead.  Hence, all three are subject to garbage
    // collection.
}

有效使用Java垃圾收集的关键是不要保留对不再需要的对象的任何引用。在二叉树中,执行

this.leftChild = null;

将使整个左子树符合垃圾回收的条件。 (也就是说,如果没有其他人保持对其中一个节点的实时引用。)

只有很少你想让垃圾收集器收集一个活动对象。这可以使用java.lang.ref.SoftReference完成。我发现它们唯一有用的是缓存。

import java.lang.ref.SoftReference;

class StoryOfMyLife {
    private final String story;
    private transient SoftReference<String[]> cachedWords;

    public StoryOfMyLife(final String story) {
        this.story = story;
        this.cachedWords = new SoftReference<String[]>(null);
    }

    public synchronized String getWordN(final int n) {
        String[] words = this.cachedWords.get();
        if (words == null) {
            // Called for the first time or cache was garbage collected.
            words = this.story.split("\\s+");
            this.cachedWords = new SoftReference<String[]>(words);
        }
        // Note that we are keeping the cache live for the duration of
        // this method by keeping the reference 'words'.  Once this
        // method returns, the cache becomes subject to garbage
        // collection again.
        return words[n];
    }
}

在这个例子中,(可能非常昂贵的)将长字符串拆分为单词只是懒惰地完成并且结果被缓存。但是,如果系统内存不足,我们允许缓存被垃圾收集,因为我们可以随时重新计算它。

您可以在Oracle's website了解有关Oracle HotSpot JVM内置垃圾收集器的更多信息。

答案 1 :(得分:0)

Java使用基于可达性的垃圾收集来管理内存,因此为了释放内存,只需确保它不再可用。

很少有Java对象需要及时清理:

即管理本机资源的那些。使用dispose()if block-scoped, try using

旁注:C ++对使用错误方法释放内存过敏:

  • 使用scope-exit进行自动存储(这就是您所使用的)。这是RAII的基础。
  • 使用delete来补充new
  • 使用delete []来补充new[]
  • 使用free来补充malloccallocrealloc