【问题标题】:How do I control garbage collector?如何控制垃圾收集器?
【发布时间】:2019-06-07 23:21:31
【问题描述】:

所以我正在编写一个算法,它可以与我的同学算法进行棋盘游戏。它基本上预见了游戏的每一个可能结果,并根据走每条路径的胜率选择最佳路径。在游戏中,每个玩家有 5 秒的时间来移动。由于这一切都在一台 PC 上运行,因此我无法在对手移动时使用处理能力或过多的内存空间。

我正在使用一个树结构,每个节点如下所示:

public class Node {

    //coordinates on the board
    private Move move;
    //winpercentage for choosing this path
    private double winPercentage;
    //is this move mine to make or is it opponents (the last person to make a move wins the game)
    private boolean odd;
    //all possible next moves
    private Set<Node> children;
    //previous move
    private Node parent;
}

我正在使用一个包装类Tree,它包含树的根以及一些用于遍历和构建结构的方法。

public class Tree {

    Node root;


    public Tree() {
        this.root = Node.createRoot();
    }

    //methods to traverse/build the tree
} 

即使在我构建了整个树并选择了我的移动之后,树仍然存储在我的对手移动期间的内存中,这是被禁止的,因为当我占用了 4GB 的 RAM 时他无法移动。我尝试将引用设置为 null 以触发 GC,但它似乎不起作用

} else if(input.equals("tree")){
    System.out.println("Showing tree structure");
    Tree tree = new Tree();
    //does all the work
    tree.mainFunctionWrapper(tree.getRoot());
    tree.setRoot(null);
    tree = null;
}

由于它全部在一个代码块中,因此我没有进一步或以前对树结构的引用。

如何让垃圾收集器工作或手动释放内存?

【问题讨论】:

  • 您可以通过不在Node 类中重复隐含信息来显着减少内存消耗。例如。 Move 是什么?棋盘上的每一步都可以只用一个起点(64 种可能性)和一个终点(63 种可能性)进行编码。这只需要 12 位,所以 short 就足够了。也没有必要保留boolean 来告诉它是哪个玩家的动作。反正它是交替的,所以每个遍历代码都应该知道这一点。但是如果你坚持,short move 字段仍然有多余的位。那么,对于winPercentage,您真的需要double 精度吗?
  • 同样,遍历代码可以保留反向链接本身,因此节点不需要parent字段。并重新考虑,是否真的必须为孩子们提供Set。 Set 像 HashSet 这样的实现喜欢使用比它们的大小更多的内存来提高查找效率。你很少需要这个(你的Node 有哈希码/相等吗?),所以数组或ArrayList(在填充后调用trimToSize() 时)会更合适并且需要更少的内存。跨度>
  • 老实说,parent 和 odd 字段是因为我的懒惰。游戏板在这里解释link。最后能够采取行动的人获胜。该板可最大为 51x51。 Move 具有 equals() 和 hashcode _Overriden_since {0;0},{0;1} 与 {0;1},{0;0} 的移动相同。它让我可以轻松搜索所有可用的动作。
  • 当顺序无关紧要时,最好在编码时将其转换为规范顺序,例如p1=(x1&lt;&lt;6)|y1; p2=(x2&lt;&lt;6)|y2; if(p1&gt;p2) { /* swap p1 &amp; p2 */ } move = (p1 &lt;&lt; 12)| p2; 这仍然适合 int 并且具有规范等价性(您只需要 ==)并且它的值也可以用作哈希码。否则,当您创建并将它们存储到 Nodes 中而不查找已经存在的等效对象时,您将拥有 Move 的 (51²)² == 6765201 不同值,甚至更多对象。我们说的是Move 对象的最小为 100MB...

标签: java memory-management tree garbage-collection


【解决方案1】:

您不能自己触发 GC,因为 System.gc() 只是一个提示。执行tree = null; 将删除引用,但Tree 对象仍分配在堆中,直到GC 决定删除它。

您最好的办法是改进您的代码,使其不需要 4 GB 堆内存,并使用 -Xmx2g 或类似选项限制 JVM。根据this answer JVM 并不热衷于将内存返回给系统。它可能会发生,但不是每 5 秒就可以完成的事情。

【讨论】:

    猜你喜欢
    • 2010-10-24
    • 1970-01-01
    • 2012-04-20
    • 1970-01-01
    • 1970-01-01
    • 2015-02-12
    • 2011-05-14
    • 2018-12-30
    • 1970-01-01
    相关资源
    最近更新 更多