查找对象作为递归的参数

时间:2016-03-09 10:56:10

标签: java memory recursion

我们正在使用迭代遍历树节点的递归,并进行一些与

的逻辑等价的计算
public static Result iterate(TreeNode node, Dictionary dictionary ) {
    Map<String, Result> accumulated = new HashMap<String, Result>();
    for (TreeNode child : node.getChildren()) {
        Result partialResult = iterate(child, dictionary);
        accumulated.put(child.getId(), partialResult);
    }
    return completeResult(accumulated);
}

现在,在递归完成时,Dicitionary对象不会发生变异。它只是用作查找表。事实上这个对象非常大。

我们将dictionary作为递归调用的参数这一事实会对内存/性能产生负面影响吗?这是一个糟糕的设计吗?

3 个答案:

答案 0 :(得分:1)

我会说你的设计是正确的,因为它应该产生正确的结果。对于它的性能,你真的需要做一些全面的测试来评估你的树形结构和字典的各种大小组合。此外,Dictionary的实施可能会在性能特征中发挥重要作用。

在内存方面,您当前的实现应该是最经济的,因为您使用现有结构,而不是复制到其他结构,以便使用更快的算法。

将字典作为参数传递具有隔离每个递归运行的好处,在字典可以在运行之间更改的情况下,并且假设您为每次运行复制字典。此外,它使您能够使用相同的代码使用不同的字典在不同的树上进行并发搜索(使用线程)。使用全局字典不允许您这样做。

答案 1 :(得分:1)

真正有趣的问题是:&#34;字典与树有什么关系?&#34;

如果需要在不同的迭代中使用多个字典,您确实会将Dictionary作为参数传递给iterate方法,就像现在一样。 (但为什么它&#34;迭代&#34;静态?)

如果Dictionary是与某个特定Tree对象关联的稳定属性,则应将其引用传递给构造函数并存储为实例字段。作为方法的迭代可以像任何其他实例字段一样访问它。

字典可能是所有Tree对象的通用和唯一吗?然后你可以提倡将Dictionary设置为一个静态类字段,你的iterate方法将把它作为一个&#34; global&#34;来访问它。

从技术上讲,上述所有内容都只传递了一个引用(&#34;地址&#34;);不涉及复制潜在的巨大物体......

答案 2 :(得分:1)

我认为这个问题归结为Java是通过引用还是值传递。有点令人困惑的是,Java总是按值传递,但是在传递对象的地方,值是对象引用。

因此,对于您的示例,方法iterate采用参数Dictionary dictionary。该对象的内部将存储在堆上。这是在所有对象之间共享的内存区域。此外,您的方法将在堆栈上拥有它自己的唯一引用。引用充当一种指针,因此您的方法可以查找dictionary

的值

当您进行递归调用时,JVM将对同一个字典对象进行新的引用,并将此引用放在堆栈上以进行新方法调用。所以现在你有两次调用迭代调用堆栈,它们都有自己对字典对象的单独引用,但堆上只有一个实际的字典对象。

如果要使用任一引用对字典对象进行更改,它将更新相同的基础对象,以便两种方法都能看到这些更改。

当方法返回时,由于字典引用是方法的本地引用,因此它将从堆栈中删除。这会将对象的引用计数减少1.如果引用的总数达到0,那么您的对象就有资格进行垃圾回收,因为没有任何东西能够看到它。

回到关于记忆的问题我不认为你需要担心。它是堆上所有数据所在的对象。相比之下,引用便宜(Java引用为8个字节)。从理论上讲,每个引用都会占用一点内存,但如果你的递归循环没有退出,你只会遇到问题。