更新:请注意,现在这个问题没有多大意义,因为callstack将独立于类型T而增长。callstack完全取决于正在处理的列表中的节点数 - 这些数据包含在节点对调用堆栈的大小没有影响。递归使用多少堆栈(从列表中删除节点)?
比方说,我有一个递归java实现了“删除节点 - 从列表”的方法看起来是这样的:
// head
public void remove(T data) {
if (data == null)
throw new IllegalArgumentException();
head = remove(head, data);
}
// other nodes of list
private ListNode remove(ListNode current, T data) {
if (current == null)
return null;
if (current.data.compareTo(data) == 0)
return current.next;
current.next = remove(current.next, data);
return current;
}
让我们进一步假设该类型T
是int
我的问题是:与我正在处理的列表大小相比,调用堆栈会得到多少(在最坏的情况下)?
什么我至今认为: 从我所看到的Java 8不优化递归(?右我的整个分析假设这是真的)。因此,我们将有一个与列表大小成线性增长的调用堆栈。
更确切地说:这个方法remove(ListNode current, T data)
将基本上在我的列表中的每个节点的调用堆栈上放置一个节点引用(32位位置上的32位)和一个int
(也是32位)。
现在,由于列表中的一个节点也由一个引用和一个节点构成,因此节点实际上与其中一个递归调用的大小几乎相同。实际上,其中一个调用甚至可能会占用更多空间(返回地址也必须被推入堆栈,对吗?或者可以通过某种方式进行优化?)。
所以,如果我是正确的,那么在最坏情况下(当要移除的元素是列表中的最后一个时),callstack基本上会像列表本身一样大!这是真的吗?如果我是正确的,那么就处理int
列表所需的堆栈而言,这意味着1或甚至更大的因子!因此,当处理大型列表时(实际上并不那么大),比如说1M人将获得一个stackoverflow,如果用stacksize(0.5M)的默认设置运行的话,我会得到一个stackoverflow。我知道这样一个事实,对于更大的数据类型来说,这个因子会更少,但是我仍然坚信在任何情况下基本上都是这样的:如果没有进行优化,那么callstack将随着列表大小线性增长 - 因此一个应该更喜欢递归过程的迭代。
一般来说,我会说,这个callstack将会以一个因子(size_of_all_arguments_in_call + size_of_return_address)/size_of_a_single_listelement
粗略线性增长,在int
列表的情况下,它几乎是一样的,对吧?请不要误解我的size_of_all_arguments
:我知道我们只传递对这些调用中对象的引用的值,而不是整个对象本身。因此,对于大型物体来说,这个因素可能不会那么戏剧化,但我仍然认为不应该接受不必要的线性空间开销。但是,对于int
的列表,该因子将是约。 1.
这个分析是否正确,或者我错过了什么?
背景:我与讨论这样做的人,试图说服我,在Java调用堆栈不会那么显着增长,并指出我缺少明显的东西(很遗憾没能告诉我什么,对我来说真的不是很明显的话) - 因为我不知道它是什么,我很想念我渴望学习;)
相关:
在我相关的问题,缺少的主要事情是多少空间将调用堆栈实际使用从
我不知道如果JVM帐户的东西,但你可以看到这篇文章和链接的重复http://stackoverflow.com/questions/17250883/is-it-possible-to-determine-how-much -space-is-on-the-stack –
找到了Java问题http://stackoverflow.com/questions/20030120/java-default-stack-size –
我认为你还需要考虑这个框架的大小: http://www.herongyang.com/JVM/Stack-Overflow-and-JVM-Stack-Frame.html – Lee