Java işleminde bellek ne tüketir?


20

java işleminin ılımlı yük altında bellek kullanımını araştırmaya çalışıyoruz.

  PID   USER    PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND
  12663 test    20   0 8378m 6.0g 4492 S   43  8.4 162:29.95 java

Gördüğünüz gibi 6Gb'de yerleşik belleğimiz var. Şimdi ilginç olan kısım şu: süreç bu parametrelerle yürütülüyor:

  • -Xmx2048m
  • -Xms2048m
  • XX: NewSize = 512
  • XX: MaxDirectMemorySize = 256m
  • ... bazıları GC ve diğer şeyler için

Bu ayarlara ve gerçek bellek kullanımına baktığımızda, bu sürecin ne kullanmasını beklediğimizin ve gerçekte ne kullandığını fark ettik.

Genellikle bellek problemlerimiz yığın dökümü analiz edilerek çözülür, ancak bu durumda belleğimiz yığın dışında bir yerde kullanılır.

Sorular: Bu kadar yüksek bellek kullanımının nedenini bulmaya yönelik adımlar ne olurdu? Hangi araçlar o süreçte hafızayı neyin kullandığını belirlememize yardımcı olabilir?

DÜZENLE 0

Hâlâ epey bir alanımız olduğu için yığınla ilgili bir sorun gibi görünmüyor:

jmap -heap 12663

sonuç (yer kazanmak için düzenlendi)

Heap Configuration:
MinHeapFreeRatio = 40
MaxHeapFreeRatio = 70
MaxHeapSize      = 2147483648 (2048.0MB)
NewSize          = 536870912 (512.0MB)
MaxNewSize       = 536870912 (512.0MB)
OldSize          = 1610612736 (1536.0MB)
NewRatio         = 7
SurvivorRatio    = 8
PermSize         = 21757952 (20.75MB)
MaxPermSize      = 85983232 (82.0MB)

New Generation: 45.7% used
Eden Space: 46.3% used
From Space: 41.4% used
To Space: 0.0% used
concurrent mark-sweep generation: 63.7% used
Perm Generation: 82.5% used

DÜZENLEME 1

pmap kullanarak oldukça fazla miktar 64Mb olduğunu görebiliriz:

pmap -x 12663 | grep rwx | sort -n -k3 | less

sonuç:

... a lot more of these 64Mb chunks
00007f32b8000000       0   65508   65508 rwx--    [ anon ] <- what are these?
00007f32ac000000       0   65512   65512 rwx--    [ anon ]
00007f3268000000       0   65516   65516 rwx--    [ anon ]
00007f3324000000       0   65516   65516 rwx--    [ anon ]
00007f32c0000000       0   65520   65520 rwx--    [ anon ]
00007f3314000000       0   65528   65528 rwx--    [ anon ] 
00000000401cf000       0  241904  240980 rwx--    [ anon ] <- Direct memory ?
000000077ae00000       0 2139688 2139048 rwx--    [ anon ] <- Heap ?

Peki bu 64Mb parçaları nelerdir? Onları ne kullanıyor? İçlerinde ne tür veriler var?

Teşekkürler


2
Aynı problemi aldım ... işte sorum. stackoverflow.com/questions/18734389/… Bu konuda bir çözümünüz var mı?
DeepNightTwo

Yanıtlar:


21

Sorun bu glibc sorunuyla ilgili olabilir .

Temel olarak, bellek ayıran birden fazla iş parçacığınız olduğunda, glibc kilit çekişmesini önlemek için ayırma yapılacak kullanılabilir alan sayısını artıracaktır. Bir arena 64Mb büyüklüğündedir. Üst sınır, çekirdek arenalarının 8 katını oluşturmaktır. Bir iş parçacığı zaten kilitli bir arenaya eriştiğinde talep üzerine oluşturulacaktır, böylece zamanla büyür.

İş parçacıkları serptiğiniz Java'da, bu hızla çok sayıda arena oluşturulmasına yol açabilir. Ve tüm bu alanlara yayılmış tahsisler var. Başlangıçta her 64 Mb arena sadece izinsiz bellek eşlenir, ancak ayırma yaparken onlar için gerçek belleği kullanmaya başlarsınız.

Pmap'niz muhtemelen aşağıdakine benzer listelere sahiptir. 324K + 65212K = 65536K, 560K + 64976K == 65536K, 620K + 64916K == 65536K'ya dikkat edin. Yani, 64Mb'ye kadar toplarlar.

00007f4394000000 324K rw - [anon]
00007f4394051000 65212K ----- [anon]
00007f4398000000 560K rw - [anon]
00007f439808c000 64976K ----- [anon]
00007f439c000000 620K rw - [anon]
00007f439c09b000 64916K ----- [anon]

Geçici çözümlere gelince : Hata, alan sayısını sınırlamak için ayarlayabileceğiniz bazı ortam parametrelerinden bahsediyor, ancak yeterince yüksek bir glibc sürümüne ihtiyacınız var.


5
Xmx ve Xms değerlerinin aynı değere ayarlanması ve web servisimizi başlatan sh komut dosyasında "export MALLOC_ARENA_MAX = 4" ortam değişkeninin ayarlanması bizim durumumuzda yardımcı oldu. Bundan önce, her 2 ila 8 saatte bir OOM Killer nedeniyle web hizmeti yeniden başlatılıyordu. Ubuntu 14.04'teki GLIBC sürümü 2.19'dur, çünkü MALLOC_ARENA_MAX ayarının çalışması için> = 2.16 olması gerekir
Kluyg

Bu cevap ve yukarıdaki yorum benim için bir cankurtaran oldu. Benim durumumda MALLOC_ARENA_MAX = 1 gerekli ve etkili oldu.
John Bachir

3

Nasıl hakkında Lamdba Probe ? Diğer şeylerin yanı sıra, aşağıdaki ekran görüntüsüne benzer bellek kullanımı arızalarını gösterebilir:

Lambda Probe bellek kullanım görünümü

Bazen pmap -x your_java_pidde yardımcı olabilir.


Cevabınız için teşekkürler. Doğru anlarsam Lambda Probe Apache Tomcat için mi? Hangi kullanmıyoruz ... Pmap ile ilgili bilgileri en üst mesaja ekleyeceğim
Konstantin S.

2

JProfiler aradığınız bir şey olabilir, ancak ücretsiz değildir. Java işleminin bellek kullanımını araştırmak için bir başka iyi ve ücretsiz araç, Oracle / Sun JDK dağıtımlarında JDK aracı olarak kullanılabilen Java VisualVM'dir. Ben kişisel olarak soruna daha bütünsel bir yaklaşım öneriyorum (yani JDK + OS + disklerini izlemek için) - bazı ağ izleme sistemlerinin kullanımı - Nagios, Verax NMS veya OpenNMS.


2
Sızıntısı yığın dışı, bu yüzden JProfiler burada gerçekten yardımcı olmayacak
Asaf Mesika

2

Sorun yığının dışında, bu yüzden en iyi aday:

JNI leak  
Allocation of direct memory buffer

Doğrudan arabellek boyutunu sınırladığınız için, bence en iyi aday JNI sızıntısı.


1

JDK'da jmap adı verilen yığın belleğinin tahsisini görüntülemek için kullanışlı bir araç var, bunun üzerine de yığın vb (Xss) var. Bellek kullanımı hakkında daha fazla bilgi almak için şu iki jmap komutunu çalıştırın:

jmap -heap <PID>
jmap -permstat <PID>

Daha da fazla bilgi almak için jconsole (JDK'da da bulunur) ile işleme bağlanabilirsiniz. Ancak Jconsole, JMX'in uygulamada yapılandırılmasını gerektirir.


Cevabınız için teşekkürler ama sorun öbek dışında bir yerde gibi görünüyor. Ben JMAP bazı bilgileri yansıtmak için üst yayınında güncellenir
Konstantin S'in

İşlemin kaç tane iş parçacığı var? Yığın boyutu çoğu platformda varsayılan olarak 2 MB'dir, bu nedenle iş parçacığı sayısıyla çarpın. Tüm "eksik" hafızayı ancak muhtemelen bazılarını hesaba katarsa ​​şaşırırdım.
HampusLi

Yaklaşık 300 iş parçacığı, pmap bilgi alınan 1Mb yığın boyutu var. Ve aynı pmap çıkışından o 100Kb daha kullanan kümelerin herhangi benzemiyor
Konstantin S.

0

JVisualVM kullanın. PermGen ve ne kadar yığın bellek kullanımda olduğunu anlatacak çeşitli farklı görüşlere sahiptir.

Sorunuzu cevaplamak için. Java, belleği beklediğinizden oldukça farklı şekilde işler.

-Xms ve -Xmx parametrelerini ayarladığınızda, JVM'ye yığınla başlamak için ne kadar bellek ayırması gerektiğini ve ayrıca maksimum olarak ne kadar ayırması gerektiğini söylersiniz.

Toplam 1m bellek kullanan ancak -Xms256m -Xmx2g'ye aktarılan bir java uygulamanız varsa, JVM kullanılan 256m bellekle kendini başlatacaktır. Bundan daha azını kullanmaz. Uygulamanızın yalnızca 1m bellek kullanması önemli değildir.

İkincisi. Yukarıdaki durumda, bir noktada uygulamanız 256m'den fazla bellek kullanıyorsa, JVM isteğe hizmet vermek için gerektiği kadar bellek ayırır. Ancak, olmayacak minimum değere yığın boyutu geri bırakın. En azından çoğu durumda değil.

Sizin durumunuzda, minimum ve maksimum belleği 2g olarak ayarladığınızdan, JVM başlangıçta 2g ayıracak ve koruyacaktır.

Java bellek yönetimi oldukça karmaşıktır ve bellek kullanımını ayarlamak kendi başına bir görev olabilir. Ancak, orada yardımcı olabilecek birçok kaynak var.

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.