Yığın boyutu neden JVM'lerde sabittir?


20

Herkes bana neden JVMs açıklayabilir miyim (çok fazla kontrol etmedim, ama hiç bu şekilde yapmadı bir görmedim) sabit bir yığın boyutu üzerinde çalıştırmak gerekir? Basit bir bitişik yığın üzerinde uygulamak daha kolay olduğunu biliyorum, ancak Sun JVM şimdi on yıldan eski, bu yüzden onları geliştirmek için zaman olmasını beklerdim.

Başlangıçta programınızın maksimum bellek boyutunu tanımlamak için 1960'larda yapılacak bir şey gibi görünüyor ve daha sonra işletim sistemi sanal bellek yönetimi ile kötü etkileşimler var (GC, değiştirilen verileri alma, Java işleminin ne kadar bellek olduğunu belirleyememe) Gerçekten işletim sistemi tarafında kullanarak, büyük miktarda VM alanı boşa harcıyor (biliyorum, 48bit makinelerinizi önemsemiyorsunuz ...)). Ayrıca, JVM (EE uygulama sunucuları, OSGi) içinde küçük işletim sistemleri oluşturmak için yapılan çeşitli üzücü girişimlerin en azından kısmen bu durumdan sorumlu olduğunu tahmin ediyorum, çünkü bir sistemde birden fazla Java işlemi çalıştırmak her zaman boşa giden kaynaklara yol açıyor çünkü her birine zirvede kullanmak zorunda kalabileceği belleği verin.

Şaşırtıcı bir şekilde, Google beklediğimden öfke fırtınaları vermedi, ancak milyonlarca insanın sabit yığın boyutunu öğrenip sadece bir gerçeği kabul ettiği için gömülmüş olabilirler.


EE uygulama sunucularının tasarımı, JVM'nin kendisi için biraz alana ihtiyaç duyduğundan ve iş parçacıkları arasında geçiş yapmak, süreçler arasında geçiş yapmaktan daha ucuz olduğu için bu "durum" olmadan bile mükemmel mantıklı olacaktır - bu, 90'ların sonlarında Java'yı büyük yapan şeylerden biridir.
Michael Borgwardt

Bu bir rütbe ve merak ediyorum ne kadar düşündüğünüzü merak ediyorum. Örneğin, bir yığın sınırınız olmasaydı GC / swap etkileşimi nasıl değişirdi? VM alanı nasıl boşa harcanır? İster kullansın ister kullanmayın 2 / 3Gb alanınızı alırsınız ve bu alanın sınırlarını zorluyorsanız, sabit veya yüzen bir yığınınız olması önemli değildir. Bu nedenle, birden fazla JVM, takas dışında herhangi bir şeyi nasıl israf eder (bunlar makinenin amacına uygun olarak yapılandırılmalıdır)?
kdgregory

2
Bu bir tür ranttır, ancak Java tabanlı bir platformun yazılması ve çalıştırılması konusunda yıllarca süren deneyim ile bilgilendirilir. Takas yapmazsanız (çünkü kaçak işlem tahsis edilecek alan bitene kadar sisteminizi 20 dakika boyunca yanıt vermeyecektir) ve kararlılık nedeniyle bellek fazla hizmetinin kapalı olması (OOM katili kurban toplamada çok iyi değildir ), VM alanını önemsiyorsunuz ve aşağıdaki kişilerin ima ettiklerinin aksine, -Xmx2048m ile bir Java VM başlatmak, tek değişkenli bir program için hemen 2GB sanal bellek (en azından Linux'taki Sun JVM'imde) tahsis edecektir.
themel

Mükemmel soru. Aynı şeyi merak ediyordum. Ama burada q'da sunulan "gerçeklerden" hangisi ve cevaplar doğrudur?
Martin Ba

Aradığınız tepkiler için, sadece güneş böcek izleyicisine eşlik edin ... örneğin burada , burada ve burada . Bunları okuyun ve öfkeli öfkeyi hissedin :)
Basic

Yanıtlar:


23

Hatalısınız. JVM'lerin yığın boyutu sabit değil, sadece sınırlı:

  • -Xmx maksimum yığın bellek boyutunu ayarlar
  • -Xms minimum yığın bellek boyutunu ayarlar

Birkaç nedenden ötürü bir üst sınır belirlemek gereklidir. İlk olarak, çöp toplayıcıya ne zaman harekete geçeceğini söyler. İkincisi, JVM'nin çok fazla bellek tüketerek tüm makineyi tıkamasını engeller. Minimum yığın boyutu, programın belleğin tükenmesini önlemek için programın en az ihtiyaç duyduğu bellek miktarını ayırmak için yararlıdır (çünkü diğer işlemler çok fazla tüketir).


9
hayır, çok fazla tekrarlanan yığın artışlarına yol açan tahsis edilmesi gerektiğinde yavaş bir başlangıçtan kaçınmak için varsayılan değer değildir, sayfalama fiziksel koç
bitiyor

@ratchetfreak benim ikinci tahminimdi ;-)
user281377 14

@ user281377 Bu durumda, o zaman C # maksimum yığın bellek boyutu olmadan nasıl iyi çalışabilir?
cmorse

cmorse: Sadece tahmin edebilirim. Java, birçok uygulamanın kaynakları paylaştığı ve kesinlikle zorlanan sınırların istendiği büyük sunucuları hedeflerken, .net daha çok PC'ler ve daha küçük, daha özel sunucular için yapılır.
user281377

@ user281377: Yığın alanı biten kullandığım Java uygulamaları genellikle çok kötü işliyor, genellikle çöküyor veya daha sonra çok kesiliyor. Ve ASP.net hem büyük hem de küçük sunucularda iyi çalışır. Gerçekten alamadım, neden varsayılan olarak, Java bu sınırı zorlar. Kararlarının ardındaki mantığı duymak isterim ... Eminim iyi bir nedenleri vardı.
cmorse

6

Cevabın Java'nın mirası ile ilgisi olduğunu düşünüyorum. Başlangıçta, kaynakların kısıtlandığı ve işlemlerin mevcut olan her şeyi basitçe çözmesini istemediğiniz gömülü sistemler için kullanılacak bir dil olarak tasarlanmıştır. Ayrıca, kaynak sınırlarını ayarlayabiliyorsanız bir sunucuda kaynak sağlamayı kolaylaştırdığı için sistem yönetimine de yardımcı olur. Tabii ki her şey kodunuz için tek bir yığın olarak görünse de, en son JVM'lerin birden fazla sürekli olmayan yığın kullandığını görüyorum.

(FWIW, bir programın bellek gereksinimlerini Apple'ın Darwin öncesi MacOS sürümlerinde [zaten kullandığım son sistem olan Sistem 7'ye kadar) ve 80'lere kadar belirtmeniz gerekiyordu.)


1
+1 - (1) soruyu gerçekten ele alan tek cevap ve (2) mantıklı olduğu için.
kdgregory

2

GC'ye biraz vermelisin mekanizmasını çalıştırmak için bunu söylemek veya programın tamamını sanal bellek alanını doldurur. GC'yi tetiklemenin birçok alternatif yolu vardır: geçen süre, tahsis sayısı, görev sayısı, muhtemelen şu anda düşünemediğim diğerleri. IMO bunların hiçbiri sadece bir bellek sınırı ayarlamak ve tahsis edilen alan bu sınıra çarptığında GC çalıştırmak kadar iyi değildir.

Anahtar doğru sınırları ayarlamaktır . -ms"Uygulamamın ne kadar belleğe ihtiyacı olduğunu" görüyorum ve-mx "asla bu miktarı aşmamalıdır" . Bir üretim dağıtımında, ikisi eşit değilse yakın olmalı ve gerçek, ölçülen gereksinimlere dayandırılmalıdır.

"Boşa" sanal bellek ile ilgili endişeleriniz yanlış: sanal, neredeyse ücretsiz. Evet, öbeğe çok büyük bir ayırma vermek, çok sayıda iş parçacığı başlatamayacağınız veya bellek eşlemeli dosya yükleyemeyeceğiniz anlamına gelir. Ancak bu uygulama tasarımının bir parçasıdır: kaynakların az olması, bunları uygulamanızın çalışmasına izin verecek şekilde bölümlendirmeniz gerekir. Eğer hafızanın tepesine kadar genişleyecek bir "C tarzı" yığın, temel sorun aynıdır, sadece belada kadar düşünmek zorunda değilsiniz.

Büyük bir yığının "harcayabileceği" tek şey takas alanıdır, çünkü tüm yazılabilir bölümler takas için bir taahhüt gerektirir. Ancak bu, sistem tasarımının bir parçasıdır: Aynı kutuda çok sayıda JVM çalıştırmak istiyorsanız, takasınızı artırın veya yığın tahsisini azaltın. Çökmeye başlarlarsa, sistemle çok fazla şey yapmaya çalışıyorsunuz; daha fazla bellek satın alın (ve hala 32 bit işlemci kullanıyorsanız, yeni bir kutu satın alın).


1
Ancak GC'yi çalıştırmak için eşiğin, program tarafından toplam bellek kullanımının geçemeyeceği sabit bir eşikle ilgisi yoktur. (Gerçekten de olmamalıdır; büyük bir yığınınız varsa ve sadece dolu olduğunda GC yapabilirsiniz, mutlaka nadir fakat uzun süre GC dönemleri olabilir). Bkz. Kuşak çöp toplama.
Ben

@ Ben - evet, haklısın. İkinci cümlem de alternatifler olduğuna dikkat çekiyor. Bununla birlikte, genel boyutta sabit boyutlu bir yığının GC'yi yönetmenin yanlış yolu olduğu konusunda hemfikir değilim. Düzgün ayarlanmış bir JVM "sağ" yığın boyutunu kullanır; tecrübelerime göre, JVM düzgün şekilde ayarlanmadığında uzun GC duraklamaları olur. Ve genellikle "doğru" yığın boyutu düşündüğünüzden çok daha küçüktür.
kdgregory

-2

User281377 söylediği gibi, yalnızca işlem ne kadar bellek üst sınırı belirlemek olabilir tüketir. Tabii ki, uygulamanın kendisi sadece ihtiyaç duyduğu alanı kaplayacaktır.

Varsayılan bir üst sınırın olup olmayacağı hem pro hem de kontra ile başka bir sorudur.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.