Java 如何正确地为垃圾收集准备类?

Java 如何正确地为垃圾收集准备类?,java,garbage-collection,Java,Garbage Collection,我正在为一个游戏设计一个决斗系统,我一直在做这个游戏,下面是这个课程的框架: public class Duel { private Champion challenger; private Champion defendant; private boolean duelStarted; private long timer; public Duel(Champion challenger, Champion defendant) {..

我正在为一个游戏设计一个决斗系统,我一直在做这个游戏,下面是这个课程的框架:

public class Duel {

    private Champion challenger;
    private Champion defendant;

    private boolean duelStarted;

    private long timer;

    public Duel(Champion challenger, Champion defendant) {..

    public void tick() {..

    public void declineDuel() {..

    public void endDuel(ResultType resultType, Champion winner, Champion forfeit) {..

    public void declareWinner(Champion player) {..

    public void declareForfeit(Champion player) {..

    private enum ResultType {..

    public Champion getChallenger() {..

    public Champion getDefendant() {..
}
该级别将分配给挑战者和被告的冠军级别

当一场决斗通过调用DueldClineEduel或DuelendDuelResultType、Champion、Champion或类似ChampionDisconnect的东西而有效结束时,我应该如何正确地设置Java垃圾收集要收集的类

我从未完全理解这一点,我是否需要将类内的所有内容设置为null,以及Duel currentDuel;在Champion.class中声明,或者我应该只将currentDuel设置为等于null,这将有效地停止引用,我假设,这就是我对这个类实例感到困惑的地方

我不太理解垃圾收集会考虑引用的类,DuelGET挑战者会被设置为仍然被引用,即使它没有被外部类触动吗? 我想我对内界和外界的引用感到困惑,有人愿意透露一些启示吗,因为我似乎不明白我在rtfm时发生了什么

我应该如何正确地设置Java垃圾收集要收集的类

你可能不需要做任何事情。如果没有其他地方对Duel的引用,则Duel对象本身有资格进行垃圾收集。。。如果决斗是涉及相关冠军对象等的最后一件事,那么这些对象也将有资格进行垃圾收集

如果Champion是通过currentDuel字段引用决斗的,就像它听起来的那样,那么如果您有一个单独的对Champion的引用,例如,您在某处有一个Champion列表,那么这些Champion将阻止对决斗进行垃圾收集,直到currentDuel设置为不同的值。但实际上,你应该考虑什么在逻辑上是有用的,而不是担心垃圾收集。。。想必,一旦决斗结束,将currentDuel设置为null是有意义的,因为冠军不再与决斗战斗。。。在那一点上,他们不会再让决斗继续下去了。虽然决斗本身不太可能需要改变什么

如果冠军本身有资格进行垃圾收集,那么你就不必担心决斗和冠军之间的引用循环——这不会阻止垃圾收集

所有这一切的原则是,我仍然可以通过任何活动线程的任何代码路径到达相关对象吗?如果您不能,那么它将有资格进行垃圾收集。如果您可以访问相关对象,那么它就不会被垃圾收集

我应该如何正确地设置Java垃圾收集要收集的类

你可能不需要做任何事情。如果没有其他地方对Duel的引用,则Duel对象本身有资格进行垃圾收集。。。如果决斗是涉及相关冠军对象等的最后一件事,那么这些对象也将有资格进行垃圾收集

如果Champion是通过currentDuel字段引用决斗的,就像它听起来的那样,那么如果您有一个单独的对Champion的引用,例如,您在某处有一个Champion列表,那么这些Champion将阻止对决斗进行垃圾收集,直到currentDuel设置为不同的值。但实际上,你应该考虑什么在逻辑上是有用的,而不是担心垃圾收集。。。想必,一旦决斗结束,将currentDuel设置为null是有意义的,因为冠军不再与决斗战斗。。。在那一点上,他们不会再让决斗继续下去了。虽然决斗本身不太可能需要改变什么

如果冠军本身有资格进行垃圾收集,那么你就不必担心决斗和冠军之间的引用循环——这不会阻止垃圾收集


所有这一切的原则是,我仍然可以通过任何活动线程的任何代码路径到达相关对象吗?如果您不能,那么它将有资格进行垃圾收集。如果您可以访问相关对象,那么它就不会被垃圾收集。

正如Jon Skeet所指出的,最好的做法是在完成对象后,将对象引用从范围之外。这不仅意味着您不需要将其设置为null,而且您的应用程序将以更具逻辑性和更易于维护的方式构建

您只需要将对象图的顶部设置为null。一旦一个对象不再是强可达的,它就可以被清除,并且它指向的任何不强可达的对象都可以被清除

在上述情况下,最简单的办法可能是放弃决斗 对象本身和所有东西都可以清理


如果怀疑内存泄漏,可以使用内存探查器查看对象上保留的引用。这将告诉您哪个引用保留在对象上。在Java中,很大一部分内存泄漏是由于对象被添加到集合中,但没有从集合中删除

正如Jon Skeet所指出的,最好的做法是在完成对象的引用后,将其移出范围。这不仅意味着您不需要将其设置为null,而且您的应用程序将以更具逻辑性和更易于维护的方式构建

您只需要将对象图的顶部设置为null。一旦一个对象不再是强可达的,它就可以被清除,并且它指向的任何不强可达的对象都可以被清除

在上面的例子中,最简单的事情可能是丢弃决斗对象本身,一切都可以清理


如果怀疑内存泄漏,可以使用内存探查器查看对象上保留的引用。这将告诉您哪个引用保留在对象上。在Java中,很大一部分内存泄漏是由于对象被添加到集合中,但没有从集合中删除

更可能的情况是,让相关变量超出范围。为了垃圾收集器,我很少需要将东西设置为null。在Java中,很大一部分内存泄漏是由于对象被添加到集合中,但没有从集合中删除。对于大多数用任何语言编写的任何类型的应用程序来说,情况不是这样吗?我一直看到这种情况,数据被粉碎到列表、字典或自定义实现中,这取决于语言,而且它们永远不会经过并删除不再使用的内容。@Christian.tucker在内存不受管理的系统中,在处理完对象后,必须可靠地调用free/delete。这有一些好处,但很容易导致错误。C/C++程序中的内存泄漏是指在Java中无法回收内存的情况,这是不可能的,因此我们在Java中赋予内存泄漏一个不同的含义,以指代任何在不需要时长时间保留的对象。@PeterLawrey-这很有趣,我从来都不知道C/C++对内存泄漏的定义,但它是有意义的。一旦内存无法回收,它也无法并行擦除,对吗?至少从内部application@Christian.tucker当应用程序死亡时,内存被回收。许多组织都有每天有计划地重新启动软件的政策,因此这些问题不会累积,而且比解决这些问题更便宜,因为解决这些问题更可能需要时间,只是让相关变量超出范围。为了垃圾收集器,我很少需要将东西设置为null。在Java中,很大一部分内存泄漏是由于对象被添加到集合中,但没有从集合中删除。对于大多数用任何语言编写的任何类型的应用程序来说,情况不是这样吗?我一直看到这种情况,数据被粉碎到列表、字典或自定义实现中,这取决于语言,而且它们永远不会经过并删除不再使用的内容。@Christian.tucker在内存不受管理的系统中,在处理完对象后,必须可靠地调用free/delete。这有一些好处,但很容易导致错误。C/C++程序中的内存泄漏是指在Java中无法回收内存的情况,这是不可能的,因此我们在Java中赋予内存泄漏一个不同的含义,以指代任何在不需要时长时间保留的对象。@PeterLawrey-这很有趣,我从来都不知道C/C++对内存泄漏的定义,但它是有意义的。一旦内存无法回收,它也无法并行擦除,对吗?至少从内部application@Christian.tucker当应用程序死亡时,内存被回收。许多组织都有每天有计划地重新启动软件的政策,因此这些问题不会累积,而且比解决这些需要时间的问题更便宜。感谢澄清,是否有垃圾收集器的处理程序允许我们打印正在收集的对象?我很确定我理解了一般的概念,但我想用不同的结果来观察它,以确保如果可能的话。@Christian.tucker:不-至少,不是在普通Java中。如果您在运行时附加了调试器代理,则可能会出现问题。您可以添加终结器,但这本身会稍微改变行为,因为垃圾收集需要更长的时间。@Christian.tucker有几种方法可以做到这一点,但是最简单的方法是覆盖finalize方法,仅为诊断目的执行此操作,如果你真的不想用它,我也不会介意
当我只是为了教育目的而进行实验时,我需要更长的时间来收集。@Christian.tucker:在几乎所有的情况下,你都应该不去管它。谢谢你的澄清,有没有让我们打印被收集对象的垃圾收集器处理程序?我很确定我理解了一般的概念,但我想用不同的结果来观察它,以确保如果可能的话。@Christian.tucker:不-至少,不是在普通Java中。如果您在运行时附加了调试器代理,则可能会出现问题。您可以添加终结器,但这本身会稍微改变行为,因为垃圾收集需要更长的时间。@Christian.tucker有几种方法可以做到这一点,但是最简单的方法是覆盖finalize方法,仅为诊断目的执行此操作,如果你根本不想使用它,也不想使用它,那么当我只是为了教育目的而进行实验时,我不介意用更长的时间来收集东西。@Christian.tucker:在几乎所有情况下,你都应该别管它。