Saya pikir yang lain telah melakukan pekerjaan yang baik dalam menjelaskan mengapa cnt> 0, tetapi tidak ada cukup detail mengenai mengapa cnt = 4, dan mengapa cnt sangat bervariasi di antara pengaturan yang berbeda. Saya akan mencoba mengisi kekosongan itu di sini.
Membiarkan
- X menjadi ukuran tumpukan total
- M menjadi ruang stack yang digunakan saat kita masuk main pertama kali
- R menjadi peningkatan ruang stack setiap kali kita masuk ke main
- P menjadi ruang tumpukan yang diperlukan untuk menjalankan
System.out.println
Saat pertama kali kita masuk ke main, space yang tersisa adalah XM. Setiap panggilan rekursif membutuhkan R lebih banyak memori. Jadi untuk 1 panggilan rekursif (1 lebih banyak dari aslinya), penggunaan memori adalah M + R. Misalkan StackOverflowError dilempar setelah C panggilan rekursif berhasil, yaitu, M + C * R <= X dan M + C * (R + 1)> X. Pada saat StackOverflowError pertama, ada memori X - M - C * R yang tersisa.
Untuk dapat menjalankannya System.out.prinln
, kita membutuhkan sejumlah P ruang yang tersisa di stack. Jika kebetulan X - M - C * R> = P, maka 0 akan dicetak. Jika P membutuhkan lebih banyak ruang, maka kami menghapus bingkai dari tumpukan, mendapatkan memori R dengan biaya cnt ++.
Ketika println
akhirnya bisa dijalankan, X - M - (C - cnt) * R> = P. Jadi jika P besar untuk sistem tertentu, maka cnt akan besar.
Mari kita lihat ini dengan beberapa contoh.
Contoh 1: Misalkan
- X = 100
- M = 1
- R = 2
- P = 1
Kemudian C = lantai ((XM) / R) = 49, dan cnt = langit-langit ((P - (X - M - C * R)) / R) = 0.
Contoh 2: Misalkan
- X = 100
- M = 1
- R = 5
- P = 12
Kemudian C = 19, dan cnt = 2.
Contoh 3: Misalkan
- X = 101
- M = 1
- R = 5
- P = 12
Maka C = 20, dan cnt = 3.
Contoh 4: Misalkan
- X = 101
- M = 2
- R = 5
- P = 12
Kemudian C = 19, dan cnt = 2.
Jadi, kita melihat bahwa sistem (M, R, dan P) dan ukuran tumpukan (X) mempengaruhi cnt.
Sebagai catatan tambahan, tidak peduli berapa banyak ruang yang catch
dibutuhkan untuk memulai. Selama tidak ada cukup ruang catch
, maka cnt tidak akan bertambah, jadi tidak ada efek eksternal.
EDIT
Saya menarik kembali apa yang saya katakan catch
. Itu memang memainkan peran. Misalkan itu membutuhkan jumlah T ruang untuk memulai. cnt mulai bertambah ketika ruang sisa lebih besar dari T, dan println
berjalan ketika ruang sisa lebih besar dari T + P. Ini menambahkan langkah ekstra ke perhitungan dan selanjutnya mengaburkan analisis yang sudah berlumpur.
EDIT
Saya akhirnya menemukan waktu untuk menjalankan beberapa eksperimen untuk mendukung teori saya. Sayangnya, teori tersebut tampaknya tidak cocok dengan eksperimen. Apa yang sebenarnya terjadi sangatlah berbeda.
Pengaturan percobaan: Server Ubuntu 12.04 dengan java default dan default-jdk. XSS mulai dari 70.000 dengan kenaikan 1 byte menjadi 460.000.
Hasilnya tersedia di: https://www.google.com/fusiontables/DataSource?docid=1xkJhd4s8biLghe6gZbcfUs3vT5MpS_OnscjWDbM
Saya telah membuat versi lain di mana setiap titik data berulang dihapus. Dengan kata lain, hanya poin yang berbeda dari sebelumnya yang ditampilkan. Ini membuatnya lebih mudah untuk melihat anomali. https://www.google.com/fusiontables/DataSource?docid=1XG_SRzrrNasepwZoNHqEAKuZlHiAm9vbEdwfsUA