Mengapa ukuran tumpukan tetap pada JVM?

20

Adakah yang bisa menjelaskan kepada saya mengapa JVM (saya tidak memeriksa terlalu banyak, tetapi saya belum pernah melihat yang tidak melakukannya dengan cara seperti itu) perlu dijalankan pada ukuran heap yang tetap? Saya tahu ini lebih mudah untuk diterapkan pada tumpukan berdekatan yang sederhana, tetapi Sun JVM sekarang berusia lebih dari satu dekade, jadi saya berharap mereka memiliki waktu untuk meningkatkan ini.

Perlu untuk menentukan ukuran memori maksimum dari program Anda pada waktu startup tampaknya merupakan hal yang harus dilakukan pada tahun 1960-an, dan kemudian ada interaksi yang buruk dengan manajemen memori virtual OS (pengambilan data yang bertukar dengan GC, ketidakmampuan untuk menentukan berapa banyak memori pada proses Java adalah benar - benar menggunakan dari sisi OS, sejumlah besar ruang VM terbuang (saya tahu, Anda tidak peduli pada mesin 48bit mewah Anda ...)). Saya juga menebak bahwa berbagai upaya menyedihkan untuk membangun sistem operasi kecil di dalam JVM (server aplikasi EE, OSGi) setidaknya sebagian untuk menyalahkan keadaan ini, karena menjalankan beberapa proses Java pada sistem selalu mengarah pada sumber daya yang terbuang karena Anda harus berikan masing-masing memori yang mungkin harus digunakan di puncak.

Anehnya, Google tidak menghasilkan badai kemarahan atas ini yang saya harapkan, tetapi mereka mungkin telah terkubur di bawah jutaan orang yang mencari tahu tentang ukuran tumpukan tetap dan hanya menerimanya sebagai fakta.

themel
sumber
Desain server aplikasi EE akan masuk akal bahkan tanpa "keadaan" ini karena JVM sendiri membutuhkan ruang, dan beralih di antara utas lebih murah daripada beralih di antara proses - itulah salah satu hal yang membuat Jawa besar di akhir tahun 90-an.
Michael Borgwardt
Ini semacam kata-kata kasar, dan saya bertanya-tanya berapa banyak pikiran Anda telah dimasukkan ke dalamnya. Misalnya, bagaimana perubahan interaksi GC / swap jika Anda tidak memiliki batas tumpukan? Bagaimana ruang VM terbuang? Anda mendapatkan ruang 2 / 3Gb apakah Anda menggunakannya atau tidak, dan jika Anda mendorong batas ruang itu, tidak masalah apakah Anda memiliki tumpukan tetap atau mengambang. Dalam hal ini, bagaimana beberapa JVM membuang sesuatu selain swap (yang harus dikonfigurasi dengan tepat untuk tujuan mesin)?
kdgregory
2
Ini adalah semacam kata-kata kasar, tetapi diinformasikan oleh pengalaman bertahun-tahun menulis dan mengoperasikan platform berbasis Java. Jika Anda tidak melakukan swap (karena itu akan membuat sistem Anda tidak responsif selama 20 menit sampai proses pelarian kehabisan ruang untuk mengalokasikan) dan memiliki memori terlalu banyak dimatikan karena alasan stabilitas (pembunuh OOM tidak pandai memilih korban ), Anda peduli dengan ruang VM, dan bertentangan dengan apa yang disiratkan orang di bawah ini, meluncurkan Java VM dengan -Xmx2048m akan segera mengalokasikan 2GB memori virtual (setidaknya di Sun JVM saya di Linux) untuk program dengan satu variabel.
themel
Pertanyaan yang sangat bagus Mengalami hal yang sama. Tapi mana dari "fakta" yang disajikan di sini dalam q dan jawabannya benar?
Martin Ba
Untuk reaksi yang Anda cari, cukup luangkan waktu bersama dengan pelacak bug matahari ... misalnya di sini , di sini dan di sini . Baca itu dan rasakan kemarahannya :)
Basic

Jawaban:

23

Anda salah. Ukuran tumpukan JVM tidak diperbaiki, hanya dibatasi:

  • -Xmx menetapkan ukuran memori tumpukan maksimum
  • -Xms menetapkan ukuran memori tumpukan minimum

Pengaturan batas atas diperlukan karena beberapa alasan. Pertama, ia memberi tahu pengumpul sampah kapan harus bertindak. Kedua, ini mencegah JVM dari menyumbat seluruh mesin dengan memakan terlalu banyak memori. Ukuran heap minimum mungkin berguna untuk menyimpan jumlah memori yang paling tidak dibutuhkan oleh program, untuk mencegah kehabisan memori (karena proses lain mengonsumsi terlalu banyak).

pengguna281377
sumber
9
tidak ada min adalah default untuk menghindari startup lambat ketika banyak perlu mengalokasikan mengakibatkan peningkatan tumpukan berulang, paging akan berurusan dengan ram fisik kehabisan
ratchet freak
@ scratchetfreak itu tebakan kedua saya ;-)
user281377
@ user281377 Jika ini masalahnya, lalu bagaimana C # bisa berjalan baik tanpa ukuran memori tumpukan maksimum?
cmorse
cmorse: Saya hanya bisa menebak. Mungkin Java ditargetkan pada server besar, di mana banyak aplikasi berbagi sumber daya dan batasan ketat yang diinginkan, sementara .net dibuat untuk PC dan server yang lebih kecil dan lebih berdedikasi.
user281377
@ user281377: Aplikasi Java yang saya gunakan yang kehabisan ruang tumpukan umumnya menanganinya sangat buruk, umumnya hanya menabrak atau menjadi sangat flakey sesudahnya. Dan ASP.net berjalan baik di server besar dan kecil. Apa yang sebenarnya tidak saya dapatkan adalah mengapa secara default, Java memberlakukan batas ini. Saya akan senang mendengar dari alasan di balik keputusan mereka ... Saya yakin mereka punya alasan yang bagus.
cmorse
6

Saya membayangkan jawabannya ada hubungannya dengan warisan Jawa. Ini awalnya dirancang sebagai bahasa yang akan digunakan untuk sistem embedded, di mana sumber daya jelas dibatasi dan Anda tidak ingin proses hanya melahap apa pun yang tersedia. Ini juga membantu administrasi sistem, karena memudahkan penyediaan sumber daya di server jika Anda dapat menetapkan batas sumber daya. Saya melihat bahwa JVM terbaru tampaknya menggunakan banyak tumpukan tidak kontinyu, meskipun tentu saja semuanya muncul sebagai tumpukan tunggal untuk kode Anda.

(FWIW, Anda harus menentukan persyaratan memori program di bawah versi MacOS pra-Darwin Apple [hingga Sistem 7, yang merupakan yang terakhir saya gunakan], yang sudah memasuki tahun 80-an.)

TMN
sumber
1
+1 - karena (1) satu-satunya jawaban yang benar-benar menjawab pertanyaan, dan (2) masuk akal.
kdgregory
2

Anda perlu memberi beberapa GC mekanisme untuk memberitahu ketika menjalankan, atau program Anda akan mengisi seluruh ruang memori virtual. Ada banyak cara alternatif untuk memicu GC: waktu yang berlalu, jumlah alokasi, jumlah penugasan, mungkin yang lain yang tidak dapat saya pikirkan saat ini. IMO tidak ada yang sebaik mengatur batas memori, dan menjalankan GC ketika ruang yang dialokasikan mencapai batas itu.

Kuncinya adalah mengatur batas yang benar . Saya melihat -mssebagai "ini adalah berapa banyak memori yang dibutuhkan aplikasi saya," dan-mx "tidak boleh melebihi jumlah ini." Dalam penyebaran produksi, keduanya harus dekat jika tidak sama, dan mereka harus didasarkan pada persyaratan aktual dan terukur.

Kekhawatiran Anda tentang memori virtual "terbuang" salah tempat: memori virtual, (hampir) gratis. Ya, memberi tumpukan terlalu besar peruntukan berarti Anda tidak dapat memulai banyak utas, atau memuat banyak file yang dipetakan memori. Tapi itu bagian dari desain aplikasi: Anda memiliki sumber daya yang langka, Anda perlu mempartisi mereka dengan cara yang memungkinkan aplikasi Anda untuk berjalan. Dalam tumpukan "C-style", yang akan meluas hingga Anda mencapai puncak memori, masalah dasarnya adalah sama, Anda tidak perlu memikirkannya sampai Anda dalam masalah.

Satu-satunya hal yang tumpukan besar "buang" adalah ruang swap, karena semua segmen yang dapat ditulis membutuhkan komitmen dari swap. Tapi itu adalah bagian dari desain sistem: jika Anda ingin memiliki banyak JVM berjalan pada kotak yang sama, baik meningkatkan swap Anda atau mengurangi penjatahan tumpukan mereka. Jika mereka mulai meronta-ronta, maka Anda mencoba melakukan terlalu banyak dengan sistem; beli lebih banyak memori (dan jika Anda masih menjalankan prosesor 32-bit, beli kotak baru).

kdgregory
sumber
1
Tetapi ambang untuk menjalankan GC tidak harus ada hubungannya dengan ambang tetap yang total penggunaan memori oleh program tidak dapat melebihi. (Memang mungkin seharusnya tidak; jika Anda memiliki tumpukan besar dan Anda hanya dapat GC ketika sudah penuh, Anda tentu memiliki periode GC yang jarang tapi lama). Lihat pengumpulan sampah generasi.
Ben
@ Ben - ya, Anda benar. Dan kalimat kedua saya menunjukkan bahwa ada alternatif. Saya tidak, bagaimanapun, setuju bahwa tumpukan ukuran tetap adalah cara yang salah untuk mengelola GC dalam kasus umum. JVM yang disetel dengan benar menggunakan ukuran tumpukan "benar"; dalam pengalaman saya, GC lama jeda terjadi ketika JVM belum disetel dengan benar. Dan seringkali ukuran tumpukan "kanan" jauh lebih kecil dari yang Anda kira.
kdgregory
-2

Seperti kata user281377, Anda hanya menentukan batas atas dari berapa banyak memori yang dapat dikonsumsi oleh proses Anda . Tentu saja, aplikasi itu sendiri hanya akan mengambil ruang yang dibutuhkannya.

Apakah harus ada batas atas default atau tidak adalah pertanyaan lain, dengan pro dan kontra.

dagnelies
sumber