Acho que os outros fizeram um bom trabalho explicando por que cnt> 0, mas não há detalhes suficientes sobre por que cnt = 4 e por que cnt varia tão amplamente entre as diferentes configurações. Vou tentar preencher esse vazio aqui.
Deixei
- X é o tamanho total da pilha
- M é o espaço de pilha usado quando entramos em main pela primeira vez
- R ser o espaço da pilha aumenta cada vez que entramos no principal
- P seja o espaço de pilha necessário para executar
System.out.println
Quando entramos pela primeira vez em main, o espaço restante é XM. Cada chamada recursiva ocupa R mais memória. Portanto, para 1 chamada recursiva (1 a mais que o original), o uso de memória é M + R. Suponha que StackOverflowError seja lançado após C chamadas recursivas bem-sucedidas, ou seja, M + C * R <= X e M + C * (R + 1)> X. No momento do primeiro StackOverflowError, há X - M - C * R de memória restante.
Para poder funcionar System.out.prinln
, precisamos de P espaço restante na pilha. Se acontecer de X - M - C * R> = P, então 0 será impresso. Se P requer mais espaço, então removemos os quadros da pilha, ganhando memória R ao custo de cnt ++.
Quando println
finalmente puder ser executado, X - M - (C - cnt) * R> = P. Portanto, se P for grande para um sistema particular, então cnt será grande.
Vejamos isso com alguns exemplos.
Exemplo 1: Suponha
- X = 100
- M = 1
- R = 2
- P = 1
Então C = piso ((XM) / R) = 49, e cnt = teto ((P - (X - M - C * R)) / R) = 0.
Exemplo 2: suponha que
- X = 100
- M = 1
- R = 5
- P = 12
Então, C = 19 e cnt = 2.
Exemplo 3: suponha que
- X = 101
- M = 1
- R = 5
- P = 12
Então C = 20 e cnt = 3.
Exemplo 4: suponha que
- X = 101
- M = 2
- R = 5
- P = 12
Então, C = 19 e cnt = 2.
Assim, vemos que tanto o sistema (M, R e P) e o tamanho da pilha (X) afetam o cnt.
Como observação lateral, não importa quanto espaço seja catch
necessário para começar. Enquanto não houver espaço suficiente para catch
, o cnt não aumentará, portanto, não há efeitos externos.
EDITAR
Retiro o que disse sobre catch
. Ele desempenha um papel. Suponha que seja necessária uma quantidade T de espaço para começar. cnt começa a aumentar quando o espaço restante é maior do que T e println
é executado quando o espaço restante é maior do que T + P. Isso adiciona uma etapa extra aos cálculos e confunde ainda mais a análise já confusa.
EDITAR
Finalmente encontrei tempo para fazer alguns experimentos para apoiar minha teoria. Infelizmente, a teoria não parece corresponder aos experimentos. O que realmente acontece é muito diferente.
Configuração da experiência: servidor Ubuntu 12.04 com java e jdk padrão. Xss começando em 70.000 em incrementos de 1 byte até 460.000.
Os resultados estão disponíveis em: https://www.google.com/fusiontables/DataSource?docid=1xkJhd4s8biLghe6gZbcfUs3vT5MpS_OnscjWDbM
Criei outra versão em que todos os pontos de dados repetidos são removidos. Em outras palavras, apenas os pontos diferentes dos anteriores são mostrados. Isso torna mais fácil ver as anomalias. https://www.google.com/fusiontables/DataSource?docid=1XG_SRzrrNasepwZoNHqEAKuZlHiAm9vbEdwfsUA