Yavaş uygulama, sık kullanılan JVM, tek CPU kurulumları ve Java 12+ ile kilitleniyor


23

Bir istemci uygulamamız var (10 yıldan fazla geliştirme ile). JDK yakın zamanda OpenJDK 11'den OpenJDK 14'e yükseltildi. Tek işlemcili (hiper iş parçacığı devre dışı) Windows 10 kurulumlarında (ve yalnızca bir kullanılabilir CPU bulunan VirtualBox makinelerinin içinde) uygulama, Java 11 ile karşılaştırıldığında oldukça yavaş başlar. Ayrıca, çoğu zaman% 100 CPU kullanır. İşlemci benzeşimini yalnızca bir CPU'ya ( c:\windows\system32\cmd.exe /C start /affinity 1 ...) ayarlamakla ilgili sorunu da yeniden oluşturabiliriz .

Uygulamayı başlatmak ve VirtualBox makinemde minimum manuel etkileşim ile bir sorgu yapmak ile bazı ölçümler:

  • OpenJDK 11.0.2: 36 saniye
  • OpenJDK 13.0.2: ~ 1.5 dakika
  • OpenJDK 13.0.2 ile -XX:-UseBiasedLocking: 46 saniye
  • OpenJDK 13.0.2 ile -XX:-ThreadLocalHandshakes: 40 saniye
  • OpenJDK 14: 5-6 dakika
  • OpenJDK 14 ile -XX:-UseBiasedLocking: 3-3,5 dakika
  • OpenJDK 15 EA Yapı 20: ~ 4,5 dakika

Yalnızca kullanılan JDK (ve belirtilen seçenekler) değiştirildi. ( -XX:-ThreadLocalHandshakesJava 14'te mevcut değildir.)

JDK 14'ün yaptıklarını günlüğe kaydetmeyi denedik -Xlog:all=debug:file=app.txt:uptime,tid,level,tags:filecount=50.

OpenJDK 11.0.2 ile günlük hatlarını her saniye saymak oldukça düzgün görünüyor:

$ cat jdk11-log/app* | grep "^\[" | cut -d. -f 1 | cut -d[ -f 2 | sort | uniq -c | sort -k 2 -n
  30710 0
  44012 1
  55461 2
  55974 3
  27182 4
  41292 5
  43796 6
  51889 7
  54170 8
  58850 9
  51422 10
  44378 11
  41405 12
  53589 13
  41696 14
  29526 15
   2350 16
  50228 17
  62623 18
  42684 19
  45045 20

Öte yandan, OpenJDK 14 ilginç sessiz dönemlere sahip gibi görünüyor:

$ cat jdk14-log/app* | grep "^\[" | cut -d. -f 1 | cut -d[ -f 2 | sort | uniq -c | sort -k 2 -n
   7726 0
   1715 5
  10744 6
   4341 11
  42792 12
  45979 13
  38783 14
  17253 21
  34747 22
   1025 28
   2079 33
   2398 39
   3016 44

Peki, 1-4, 7-10 ve 14-20 saniye arasında ne oluyor?

...
[0.350s][7248][debug][class,resolve        ] jdk.internal.ref.CleanerFactory$1 java.lang.Thread CleanerFactory.java:45
[0.350s][7248][debug][class,resolve        ] jdk.internal.ref.CleanerImpl java.lang.Thread CleanerImpl.java:117
[0.350s][7248][info ][biasedlocking        ] Aligned thread 0x000000001727e010 to 0x000000001727e800
[0.350s][7248][info ][os,thread            ] Thread started (tid: 2944, attributes: stacksize: default, flags: CREATE_SUSPENDED STACK_SIZE_PARAM_IS)
[0.350s][6884][info ][os,thread            ] Thread is alive (tid: 6884).
[0.350s][6884][debug][os,thread            ] Thread 6884 stack dimensions: 0x00000000175b0000-0x00000000176b0000 (1024k).
[0.350s][6884][debug][os,thread            ] Thread 6884 stack guard pages activated: 0x00000000175b0000-0x00000000175b4000.
[0.350s][7248][debug][thread,smr           ] tid=7248: Threads::add: new ThreadsList=0x0000000017254500
[0.350s][7248][debug][thread,smr           ] tid=7248: ThreadsSMRSupport::free_list: threads=0x0000000017253d50 is freed.
[0.350s][2944][info ][os,thread            ] Thread is alive (tid: 2944).
[0.350s][2944][debug][os,thread            ] Thread 2944 stack dimensions: 0x00000000177b0000-0x00000000178b0000 (1024k).
[0.350s][2944][debug][os,thread            ] Thread 2944 stack guard pages activated: 0x00000000177b0000-0x00000000177b4000.
[0.351s][2944][debug][class,resolve        ] java.lang.Thread java.lang.Runnable Thread.java:832
[0.351s][2944][debug][class,resolve        ] jdk.internal.ref.CleanerImpl jdk.internal.misc.InnocuousThread CleanerImpl.java:135
[0.351s][2944][debug][class,resolve        ] jdk.internal.ref.CleanerImpl jdk.internal.ref.PhantomCleanable CleanerImpl.java:138
[0.351s][2944][info ][biasedlocking,handshake] JavaThread 0x000000001727e800 handshaking JavaThread 0x000000000286d800 to revoke object 0x00000000c0087f78
[0.351s][2944][debug][vmthread               ] Adding VM operation: HandshakeOneThread
[0.351s][6708][debug][vmthread               ] Evaluating non-safepoint VM operation: HandshakeOneThread
[0.351s][6708][debug][vmoperation            ] begin VM_Operation (0x00000000178af250): HandshakeOneThread, mode: no safepoint, requested by thread 0x000000001727e800

# no log until 5.723s

[5.723s][7248][info ][biasedlocking          ]   Revoked bias of currently-unlocked object
[5.723s][7248][debug][handshake,task         ] Operation: RevokeOneBias for thread 0x000000000286d800, is_vm_thread: false, completed in 94800 ns
[5.723s][7248][debug][class,resolve          ] java.util.zip.ZipFile$CleanableResource java.lang.ref.Cleaner ZipFile.java:715
[5.723s][7248][debug][class,resolve          ] java.lang.ref.Cleaner jdk.internal.ref.CleanerImpl$PhantomCleanableRef Cleaner.java:220
[5.723s][7248][debug][class,resolve          ] java.util.zip.ZipFile$CleanableResource java.util.WeakHashMap ZipFile.java:716
...

İkinci duraklama biraz sonra:

...
[6.246s][7248][info ][class,load              ] java.awt.Graphics source: jrt:/java.desktop
[6.246s][7248][debug][class,load              ]  klass: 0x0000000100081a00 super: 0x0000000100001080 loader: [loader data: 0x0000000002882bd0 of 'bootstrap'] bytes: 5625 checksum: 0025818f
[6.246s][7248][debug][class,resolve           ] java.awt.Graphics java.lang.Object (super)
[6.246s][7248][info ][class,loader,constraints] updating constraint for name java/awt/Graphics, loader 'bootstrap', by setting class object
[6.246s][7248][debug][jit,compilation         ]   19       4       java.lang.Object::<init> (1 bytes)   made not entrant
[6.246s][7248][debug][vmthread                ] Adding VM operation: HandshakeAllThreads
[6.246s][6708][debug][vmthread                ] Evaluating non-safepoint VM operation: HandshakeAllThreads
[6.246s][6708][debug][vmoperation             ] begin VM_Operation (0x000000000203ddf8): HandshakeAllThreads, mode: no safepoint, requested by thread 0x000000000286d800
[6.246s][6708][debug][handshake,task          ] Operation: Deoptimize for thread 0x00000000026b0800, is_vm_thread: true, completed in 1400 ns
[6.246s][6708][debug][handshake,task          ] Operation: Deoptimize for thread 0x00000000026bb800, is_vm_thread: true, completed in 700 ns
[6.246s][6708][debug][handshake,task          ] Operation: Deoptimize for thread 0x00000000026ef800, is_vm_thread: true, completed in 100 ns
[6.246s][6708][debug][handshake,task          ] Operation: Deoptimize for thread 0x00000000026f0800, is_vm_thread: true, completed in 100 ns
[6.246s][6708][debug][handshake,task          ] Operation: Deoptimize for thread 0x00000000026f1800, is_vm_thread: true, completed in 100 ns
[6.246s][6708][debug][handshake,task          ] Operation: Deoptimize for thread 0x00000000026f4800, is_vm_thread: true, completed in 100 ns
[6.247s][6708][debug][handshake,task          ] Operation: Deoptimize for thread 0x0000000002768800, is_vm_thread: true, completed in 100 ns
[6.247s][6708][debug][handshake,task          ] Operation: Deoptimize for thread 0x000000000276e000, is_vm_thread: true, completed in 100 ns
[6.247s][6708][debug][handshake,task          ] Operation: Deoptimize for thread 0x0000000017268800, is_vm_thread: true, completed in 100 ns
[6.247s][6708][debug][handshake,task          ] Operation: Deoptimize for thread 0x000000001727e800, is_vm_thread: true, completed in 800 ns

# no log until 11.783s

[11.783s][6708][debug][handshake,task          ] Operation: Deoptimize for thread 0x000000000286d800, is_vm_thread: true, completed in 6300 ns
[11.783s][6708][info ][handshake               ] Handshake "Deoptimize", Targeted threads: 11, Executed by targeted threads: 0, Total completion time: 5536442500 ns
[11.783s][6708][debug][vmoperation             ] end VM_Operation (0x000000000203ddf8): HandshakeAllThreads, mode: no safepoint, requested by thread 0x000000000286d800
[11.783s][7248][debug][protectiondomain        ] Checking package access
[11.783s][7248][debug][protectiondomain        ] class loader: a 'jdk/internal/loader/ClassLoaders$AppClassLoader'{0x00000000c0058628} protection domain: a 'java/security/ProtectionDomain'{0x00000000c058b948} loading: 'java/awt/Graphics'
[11.783s][7248][debug][protectiondomain        ] granted
[11.783s][7248][debug][class,resolve           ] sun.launcher.LauncherHelper java.awt.Graphics LauncherHelper.java:816 (reflection)
[11.783s][7248][debug][class,resolve           ] jdk.internal.reflect.Reflection [Ljava.lang.reflect.Method; Reflection.java:300
[11.783s][7248][debug][class,preorder          ] java.lang.PublicMethods$MethodList source: C:\Users\example\AppData\Local\example\stable\jdk\lib\modules
...

Sonra üçüncüsü:

...
[14.578s][7248][debug][class,preorder          ] java.lang.InheritableThreadLocal source: C:\Users\example\AppData\Local\example\stable\jdk\lib\modules
[14.578s][7248][info ][class,load              ] java.lang.InheritableThreadLocal source: jrt:/java.base
[14.578s][7248][debug][class,load              ]  klass: 0x0000000100124740 super: 0x0000000100021a18 loader: [loader data: 0x0000000002882bd0 of 'bootstrap'] bytes: 1338 checksum: 8013ed55
[14.578s][7248][debug][class,resolve           ] java.lang.InheritableThreadLocal java.lang.ThreadLocal (super)
[14.578s][7248][debug][jit,compilation         ]  699       3       java.lang.ThreadLocal::get (38 bytes)   made not entrant
[14.578s][7248][debug][vmthread                ] Adding VM operation: HandshakeAllThreads
[14.578s][6708][debug][vmthread                ] Evaluating non-safepoint VM operation: HandshakeAllThreads
[14.578s][6708][debug][vmoperation             ] begin VM_Operation (0x000000000203d228): HandshakeAllThreads, mode: no safepoint, requested by thread 0x000000000286d800
[14.578s][6708][debug][handshake,task          ] Operation: Deoptimize for thread 0x00000000026b0800, is_vm_thread: true, completed in 1600 ns
[14.578s][6708][debug][handshake,task          ] Operation: Deoptimize for thread 0x00000000026bb800, is_vm_thread: true, completed in 900 ns
[14.578s][6708][debug][handshake,task          ] Operation: Deoptimize for thread 0x00000000026ef800, is_vm_thread: true, completed in 100 ns
[14.578s][6708][debug][handshake,task          ] Operation: Deoptimize for thread 0x00000000026f0800, is_vm_thread: true, completed in 100 ns
[14.578s][6708][debug][handshake,task          ] Operation: Deoptimize for thread 0x00000000026f1800, is_vm_thread: true, completed in 100 ns
[14.578s][6708][debug][handshake,task          ] Operation: Deoptimize for thread 0x00000000026f4800, is_vm_thread: true, completed in 0 ns
[14.578s][6708][debug][handshake,task          ] Operation: Deoptimize for thread 0x0000000002768800, is_vm_thread: true, completed in 0 ns
[14.578s][6708][debug][handshake,task          ] Operation: Deoptimize for thread 0x000000000276e000, is_vm_thread: true, completed in 0 ns
[14.578s][6708][debug][handshake,task          ] Operation: Deoptimize for thread 0x0000000017268800, is_vm_thread: true, completed in 0 ns
[14.579s][6708][debug][handshake,task          ] Operation: Deoptimize for thread 0x000000001727e800, is_vm_thread: true, completed in 900 ns

# no log until 21.455s

[21.455s][6708][debug][handshake,task          ] Operation: Deoptimize for thread 0x000000000286d800, is_vm_thread: true, completed in 12100 ns
[21.455s][6708][info ][handshake               ] Handshake "Deoptimize", Targeted threads: 11, Executed by targeted threads: 0, Total completion time: 6876829000 ns
[21.455s][6708][debug][vmoperation             ] end VM_Operation (0x000000000203d228): HandshakeAllThreads, mode: no safepoint, requested by thread 0x000000000286d800
[21.455s][7248][debug][class,resolve           ] sun.security.jca.Providers java.lang.InheritableThreadLocal Providers.java:39
[21.455s][7248][info ][class,init              ] 1251 Initializing 'java/lang/InheritableThreadLocal'(no method) (0x0000000100124740)
[21.455s][7248][debug][class,resolve           ] java.lang.InheritableThreadLocal java.lang.ThreadLocal InheritableThreadLocal.java:57
[21.456s][7248][debug][class,preorder          ] sun.security.jca.ProviderList source: C:\Users\example\AppData\Local\example\stable\jdk\lib\modules
[21.456s][7248][info ][class,load              ] sun.security.jca.ProviderList source: jrt:/java.base
[21.456s][7248][debug][class,load              ]  klass: 0x00000001001249a8 super: 0x0000000100001080 loader: [loader data: 0x0000000002882bd0 of 'bootstrap'] bytes: 11522 checksum: bdc239d2
[21.456s][7248][debug][class,resolve           ] sun.security.jca.ProviderList java.lang.Object (super)
...

Aşağıdaki iki satır ilginç görünüyor:

[11.783s][6708][info ][handshake               ] Handshake "Deoptimize", Targeted threads: 11, Executed by targeted threads: 0, Total completion time: 5536442500 ns
[21.455s][6708][info ][handshake               ] Handshake "Deoptimize", Targeted threads: 11, Executed by targeted threads: 0, Total completion time: 6876829000 ns

Bu tokalaşmaların 5.5 ve 6.8 saniye sürmesi normal mi?

Bu komutla çalışan update4j demo uygulaması ( uygulamamızla tamamen ilgisiz ) ile aynı yavaşlamayı (ve benzer günlükleri) yaşadım :

Z:\swing>\jdk-14\bin\java -Xlog:all=debug:file=app.txt:uptime,tid,level,tags:filecount=50 \
    -jar update4j-1.4.5.jar --remote http://docs.update4j.org/demo/setup.xml

Tek CPU'lu Windows 10 kurulumlarında uygulamamızı tekrar daha hızlı hale getirmek için nelere dikkat etmeliyim? Uygulamamızdaki bir şeyi değiştirerek veya JVM bağımsız değişkenleri ekleyerek bunu düzeltebilir miyim?

Bu bir JDK hatası mı, bildirmeliyim?

2020-04-25 güncellemesi:

Gördüğüm kadarıyla günlük dosyaları GC günlükleri de içeriyor. Bunlar ilk GC günlükleri:

$ cat app.txt.00 | grep "\[gc"
[0.016s][7248][debug][gc,heap          ] Minimum heap 8388608  Initial heap 60817408  Maximum heap 1073741824
[0.017s][7248][info ][gc,heap,coops    ] Heap address: 0x00000000c0000000, size: 1024 MB, Compressed Oops mode: 32-bit
[0.018s][7248][info ][gc               ] Using Serial
[22.863s][6708][info ][gc,start                ] GC(0) Pause Young (Allocation Failure)
[22.863s][6708][debug][gc,heap                 ] GC(0) Heap before GC invocations=0 (full 0): def new generation   total 17856K, used 15936K [0x00000000c0000000, 0x00000000c1350000, 0x00000000d5550000)
...

Maalesef üçüncü duraklamadan sonra başladığı için ilgili görünmüyor.

2020-04-26 güncellemesi:

OpenJDK 14 ile uygulama (tek CPU) VirtualBox makinemde% 100 CPU kullanıyor (bir i7-6600U CPU üzerinde çalışıyor). Sanal makinede 3,5 GB RAM var. Görev Yöneticisi'ne göre% 40 + ücretsiz ve disk etkinliği% 0 (sanırım bu takas yok). Sanal makineye başka bir CPU eklemek (ve fiziksel makineler için hiper iş parçacığını etkinleştirmek) uygulamayı tekrar yeterince hızlı hale getirir. Sadece merak ediyorum, JKM'yi çok çekirdekli / hiper iş parçacıklı CPU'larda daha hızlı hale getirmek için JDK geliştirme sırasında (nadir) tek CPU makinelerinde performans kaybı yapmak kasıtlı bir takas mıydı?


3
-Xlog:all=debugGC günlük kaydını açar mı ? Bu herhangi bir duraklama için ilk tahminim olurdu.
kichik

Bir profil oluşturucu ile çalışmayı ve sonuçları karşılaştırmayı denediniz mi? Bunun doğal bir şey olacağını düşünüyorum.
Axel

1
ayrıca windows sistem mesajlarını kontrol edin, jdk 14 için farklı bir yapı deneyin.
Khanna111

1
@ Yan.F: OpenJDK 11 sonsuza dek desteklenmeyecek, yeni sürümleri ve hataları hazırlama zamanı. Ayrıca, bir JDK hatası gibi görünüyor - bu düzeltilebilir veya düzeltilmeyebilir, ancak başkalarına da yardımcı olabilir. Her neyse, benim için çoğunlukla merak. Öte yandan şimdi müşterilerimize uygulamamızın minimum sistem gereksinimleri olarak ne söyleyeceklerini anlatmak istiyorum.
palacsint

1
@ Khanna111: Evet, cevap olarak yeni yazdım.
palacsint

Yanıtlar:


6

Deneyimlerime göre JDK'larla ilgili performans sorunları çoğunlukla aşağıdakilerden biriyle ilgilidir:

  • Jit derleme
  • VM yapılandırması (yığın boyutları)
  • GC algoritması
  • Bilinen iyi çalışan uygulamaları bozan JVM / JDK'daki değişiklikler
  • (Oh, ve sınıf yüklemesinden bahsetmeyi unuttum ...)

OpenJDK11'den beri sadece varsayılan JVM yapılandırmasını kullanıyorsanız, belki daha belirgin seçeneklerden bazılarını GC, Yığın boyutu vb. Gibi sabit değerlere ayarlamanız gerekir.

Belki bazı grafik analiz aracı sorununuzu bulmanıza yardımcı olabilir. Retrace, AppDynamics veya FlightRecorder ve benzerleri gibi. Bunlar, belirli bir zamanda yığın, gc döngüleri, RAM, iş parçacıkları, CPU yükü vb. Genel durumu hakkında günlük dosyalarının sağlayabileceğinden daha fazla genel bakış sağlar.

Uygulamanızın çalışmanın ilk saniyesi içinde (OpenJDK11 altında) günlüğe yaklaşık 30710 satır yazdığını doğru anladım mı? Neden "sadece" ilk saniyede OpenJDK14 altında yaklaşık 7 bin satır yazıyor? Bu, bana farklı JVM'lerde yeni başlayan bir uygulama için büyük bir fark gibi görünüyor ... Örneğin, günlüğe dökülen yüksek miktarda İstisna yığınları olmadığından emin misiniz?
Diğer sayılar bazen daha da yüksektir, bu nedenle yavaşlamalar istisna günlüğü ile ilgilidir? Ya da RAM azalırsa, takas bile?
Aslında, bir uygulama günlüğe bir şey yazmazsa, bu sorunsuz bir şekilde çalışmanın bir işareti olduğunu düşünüyorum (tamamen bu süre içinde dondurulmadıkça). 12-22 saniye arasında ne oluyor (burada OpenJDK14 durumunda) beni daha fazla ilgilendiren şey ... kaydedilen çizgiler çatıdan geçiyor ... neden ?
Ve daha sonra günlüğü nedeni nedir ... 1-2k hakkında hatlarının her zaman düşük değerlere iner o ?? (iyi, belki de ikinci 22'de gc vuruyor ve bazı şeyleri çözen bir tabula rasa yapıyor mu ...?)

Başka bir şey, "tek CPU" makineleri hakkında açıklama olabilir. Bu da "tek çekirdekli" anlamına geliyor mu (Idk, belki de yazılımınız eski donanıma veya başka bir şeye göre uyarlanmıştır)? Ve "tek CPU" VM'leri bu makinelerde mi çalışıyor? Ama sanırım, bu varsayımlar hakkında yanılıyorum, çünkü neredeyse tüm CPU'lar günümüzde çok çekirdekli ... ama belki çok iş parçacıklı bir sorun (kilitlenme) sorunu üzerinde araştırma yapardım.


2
Lütfen gönderilerinizde imza veya slogan kullanmayın, tekrarlayan "GL ve HF" gürültü ve yayınınızın içeriğinden dikkatinizi dağıtır. Daha fazla bilgi için meta.stackexchange.com/help/behavior adresine bakın .
meagar

1
"Uygulamanızın çalışmanın ilk saniyesinde (OpenJDK11 altında) günlüğe yaklaşık 30710 satır yazdığını doğru anladım mı?" - Evet haklısın.
palacsint

1
"Günlüğe dökülen yüksek miktarda İstisna yığınları olmadığından emin misiniz?" - Günlük temiz, orada garip bir şey bulamadım, uygulama düzgün çalışıyor (çok yavaş çalışması dışında).
palacsint

1
GC 22. saniyede başlıyor ve uygulama bundan sonra yavaş kalıyor. Soruyu da güncelledim. Update4j demo uygulamasının da aynı sorunu yaşadığını lütfen unutmayın. Cevap için teşekkür ederim!
palacsint

1
Bir saniyede 30k + günlük satırları oldukça büyük ... kabul etmiyor musunuz? Bu kadar kısa sürede bu yüksek miktarda günlük satırını kabul etmek için nelerin kaydedilmesinin yararlı olabileceğini gerçekten merak ediyorum ... Günlük kaydını tamamen kapatmayı ve uygulamayı bu modda profillemeyi denediniz mi? (Merak ediyorum, ancak update4j davranışını ima ettiğiniz için giriş yapmanın gerçekten bir etkisi yoktur)
Antares

5

% 100 CPU "çoğu zaman" kullandığından ve Java 14 ile 10 kat daha uzun (!) Sürdüğü için, Java 14'te CPU'nuzun% 90'ını boşa harcadığınız anlamına gelir.

Yığın boşluk kalmadı kutu Eğer GC zaman bir sürü harcama, ama o out hüküm var gibi gibi bunu.

Önyargılı kilitleme seçeneğini değiştirdiğinizi ve bunun önemli bir fark yarattığını fark ettim. Bu, belki de programınızın birden fazla iş parçacığında çok sayıda eşzamanlı çalışma yaptığını söylüyor. Programınızın Java 14'te görünen, ancak Java 10'da görünmeyen bir eşzamanlılık hatası olması mümkündür. Bu, başka bir CPU eklemenin neden onu iki kattan daha hızlı yaptığını açıklayabilir.

Eşzamanlılık hataları genellikle şanssızken ortaya çıkar ve tetikleyici hashmap organizasyonunda bir değişiklik gibi bir şey olabilirdi.

İlk olarak, mümkünse, uyumak yerine meşgul bekleyen olabilecek döngüler olup olmadığını kontrol edin.

Ardından, örnekleme modunda bir profiler çalıştırın (jvisualvm yapacak) ve toplam sürenin çok daha büyük bir bölümünü alan yöntemleri aramalıdır. Performansınız 10 kat azaldığı için, içerideki herhangi bir sorun gerçekten atlanmalıdır.


Önyargılı Kilitleme geçmişte gerekliydi ama günümüzde çok fazla değil ve varsayılan olarak devre dışı bırakılması ve daha sonra kaldırılması öneriliyor
JohannesB

2

Bu ilginç bir konudur ve denenmesi ve toplanması ve toplanması gereken birçok permütasyon ve kombinasyon olduğu için, onu daraltmak için belirsiz bir çaba gerektirecektir.

Görünüşe göre bir süredir bu konuda çözüm bulunmuyor. Belki de bu durumun artması gerekebilir.

DÜZENLEME 2: "ThreadLocalHandshakes" kullanımdan kaldırıldığından ve kilitlemenin devam ettiğini varsayabiliriz, bu senaryoyu hızlandırmak için "UseBiasedLocking" olmadan denemenizi öneririz.

Bununla birlikte, daha fazla veri toplamak ve sorunu yalıtmaya çalışmak için bazı öneriler var.

  1. Birden fazla çekirdek ayırın [Bunu denediğinizi görüyorum ve sorun ortadan kalkıyor. Diğerlerinden önce gelen bir iş parçacığı / s yürütme ile ilgili bir sorun gibi görünüyor. Aşağıdaki 7'ye bakınız)
  2. Daha fazla yığın ayırın (belki de v14'ün talepleri önceki jdk'lerden daha fazladır)
  3. Win 10 VB'ye daha fazla bellek ayırın.
  4. İşletim sistemi sistem mesajlarını kontrol edin (davanızda 10 kazanın)
  5. Sanallaştırılmamış bir Win 10'da çalıştırın.
  6. Farklı bir jdk 14 yapısını deneyin
  7. Her birkaç aralıkta (veya profil) bir iplik dökümü yapın. Yalnızca hangi iş parçacığının çalıştığını analiz edin. Belki de adil zaman paylaşımı için bir ayar vardır. Belki daha yüksek öncelikli bir iş parçacığı vardır. Bu iş parçacığı nedir ve ne yapıyor? Linux'ta, bir işlemle ilişkili hafif işlemleri (iş parçacıkları) ve gerçek zamanlı olarak durumunu belirtebilirsiniz. Win 10'da benzer bir şey mi var?
  8. CPU kullanımı? % 100 veya daha az? CPU veya mem tarafından kısıtlandı mı? Servis iş parçacığında% 100 CPU? Hangi hizmet dizisi?
  9. Açıkça bir GC algo oluşturdunuz mu?

GC, yığın yeniden boyutlandırma, sanallaştırılmış kapsayıcılarla ilgili sorunlar vb. İle ilgili sürümlerde kişisel olarak şahit oldum.

Bunun kolay bir cevabı yok, bence, özellikle bu soru bir süredir var olduğu için. Ama en iyisini deneyebiliriz ve bu izolasyon adımlarından bazılarının sonucunu bize bildirebiliriz.

DÜZENLEME 1: güncellenen sorudan, bir GC veya tek bir çekirdeği eşit olmayan bir şekilde ele geçiren başka bir hizmet iş parçacığı ile ilgili gibi görünüyor (Konu-Yerel El Sıkışmalar)?


Performans ve bellek kullanımındaki ani farklılıkları açıklayabilirse, istemciden 32 bit sistemlerde Java ergonomisinden bir istemciden farklı GC ve Katmanlı Derleme ile sunucu sınıfı vm'ye geçişi tetiklemek için kullanılan ekstra bir CPU çekirdeği eklemek, evet JVM performans karmaşık 😁
JohannesB

3
Java ergonomisi (varsayılan ayarlar) 1 CPU için hala farklıdır (örneğin: -XX: + UseSerialGC) veya 2 CPU (örn: G1GC, LoopStripMiningIter = 1000, ... ShortLoop = 100) Ancak -XX: + Tüm parametreleri aynı veya benzer çalışan update4j'ye ayarladığım PrintFlagsFinal, cmd.exe / C başlatma / yakınlık 0x1 ile 2 CPU yerine sadece bir tane ile başlamak için son derece yavaştı (ancak 0x3 ile son derece hızlı - böylece 2 cpus (1 + 10 ikili)). Herhangi bir GC yükünü önlemek için tasarlanmış Epsilon GC kullanarak herhangi bir çöp toplayıcısını suçlayamayacağımızı doğruladım. TieredCompilation ancak etkin
JohannesB

Anlıyorum. Epsilon GC ile sanki yavaşmış gibi görünüyor. Bu durumda, nerede takıldığını değerlendirmek için iş parçacığı durumları ve dökümleri bir yol olabilir. Hem Java dünyasında hem de OS dünyasında (hatırlıyorsam linux gcore idi)
Khanna111

2

TL; DR : Bu bir OpenJDK gerilemesi.

Ben bunun dışında değildim ama basit bir merhaba dünya ile sorunu yeniden üretebilir:

public class Main {
    public static void main(String[] args) {
        System.out.println("Hello world");
    }
}

Bu iki toplu iş dosyasını kullandım:

main-1cpu.bat, bu javaişlemi yalnızca bir CPU ile sınırlar:

c:\windows\system32\cmd.exe /C start /affinity 1 \
    \jdk-14\bin\java \
    -Xlog:all=trace:file=app-1cpu.txt:uptime,tid,level,tags:filecount=50 \
    Main

main-full.bat, javaişlem her iki CPU'yu da kullanabilir:

c:\windows\system32\cmd.exe /C start /affinity FF \
    \jdk-14\bin\java \
    -Xlog:all=trace:file=app-full.txt:uptime,tid,level,tags:filecount=50 \
    Main

(Farklar affinitygünlük dosyasının değeri ve adıdır. Daha kolay okumak için sardım, ancak \büyük olasılıkla Windows ile çalışmaz.)

VirtualBox'ta Windows 10 x64'te birkaç ölçüm (iki CPU ile):

PS Z:\main> Measure-Command { .\main-1cpu.bat }

...    
TotalSeconds      : 7.0203455
...


PS Z:\main> Measure-Command { .\main-full.bat }

...
TotalSeconds      : 1.5751352
...


PS Z:\main> Measure-Command { .\main-full.bat }

...
TotalSeconds      : 1.5585384
...


PS Z:\main> Measure-Command { .\main-1cpu.bat }

...
TotalSeconds      : 23.6482685
...

Üretilen traceloglar, soruda görebileceğiniz benzer duraklamalar içerir.

Koşu Maintracelogs olmadan hızlıdır ancak fark yine tek CPU ve iki işlemci versiyonu arasında görülebilir: ~ 4-7 saniye vs ~ 400 ms.

Bu bulguları hotspot-dev @ openjdk posta listesine gönderdim ve devs orada bunun JDK'nın daha iyi işleyebileceği bir şey olduğunu doğruladı . Sen bulabileceğiniz düzeltmeleri gerekiyordu çok dizisindeki. Umarım OpenJDK 15'te düzeltilecektir.


1

Yavaş disklere giriş yaparken dikkatli olun, uygulamanızı yavaşlatır:

https://engineering.linkedin.com/blog/2016/02/eliminating-large-jvm-gc-pauses-caused-by-background-io-traffic

Ancak CPU hala meşgul olduğundan ve iş parçacığı-yerel el sıkışma sayesinde tüm iş parçacıklarının güvenli bir noktaya gelmesini beklemenize gerek olmadığı için sorunun nedeni gibi görünmüyor: https: // openjdk. java.net/jeps/312

Ayrıca doğrudan sorunla ilgili değil, daha genel olarak başlangıç ​​zamanı için donanımınızdan daha fazla performans elde etmek istiyorsanız, AppCDS'ye (sınıf veri paylaşımı) bir göz atın:

https://blog.codefx.org/java/application-class-data-sharing/

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.