Ứng dụng chậm, JVM thường xuyên bị treo với các thiết lập CPU đơn và Java 12+


24

Chúng tôi có một ứng dụng khách (với hơn 10 năm phát triển). JDK của nó đã được nâng cấp từ OpenJDK 11 lên OpenJDK 14 gần đây. Trên các CPU đơn (siêu phân luồng bị vô hiệu hóa) thiết lập Windows 10 (và bên trong các máy VirtualBox chỉ có một CPU khả dụng), ứng dụng khởi động khá chậm so với Java 11. Hơn nữa, hầu hết thời gian, nó sử dụng CPU 100%. Chúng tôi cũng có thể tái tạo vấn đề bằng cách đặt ái lực của bộ xử lý thành chỉ một CPU ( c:\windows\system32\cmd.exe /C start /affinity 1 ...).

Một số phép đo khi khởi động ứng dụng và thực hiện truy vấn với tương tác thủ công tối thiểu trong máy VirtualBox của tôi:

  • OpenJDK 11.0.2: 36 giây
  • OpenJDK 13.0.2: ~ 1,5 phút
  • OpenJDK 13.0.2 với -XX:-UseBiasedLocking: 46 giây
  • OpenJDK 13.0.2 với -XX:-ThreadLocalHandshakes: 40 giây
  • OpenJDK 14: 5-6 phút
  • OpenJDK 14 với -XX:-UseBiasedLocking: 3-3,5 phút
  • OpenJDK 15 EA Build 20: ~ 4,5 phút

Chỉ JDK được sử dụng (và các tùy chọn được đề cập) đã được thay đổi. ( -XX:-ThreadLocalHandshakeskhông có sẵn trong Java 14.)

Chúng tôi đã thử đăng nhập những gì JDK 14 làm với -Xlog:all=debug:file=app.txt:uptime,tid,level,tags:filecount=50.

Đếm các dòng nhật ký cho mỗi giây có vẻ khá trơn tru với OpenJDK 11.0.2:

$ 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

Mặt khác, OpenJDK 14 dường như có những khoảng thời gian yên tĩnh thú vị:

$ 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

Vậy, chuyện gì đang xảy ra giữa giây 1-4, 7-10 và 14-20?

...
[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
...

Tạm dừng thứ hai một chút sau:

...
[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
...

Sau đó, cái thứ ba:

...
[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)
...

Hai dòng sau có vẻ thú vị:

[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

Điều đó có bình thường không khi những cái bắt tay này mất 5,5 và 6,8 giây?

Tôi đã trải qua sự chậm lại tương tự (và các bản ghi tương tự) với ứng dụng demo update4j (hoàn toàn không liên quan đến ứng dụng của chúng tôi) chạy bằng lệnh này:

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

Tôi nên tìm kiếm gì để làm cho ứng dụng của chúng tôi nhanh hơn một lần nữa trong các thiết lập Windows 10 CPU đơn? Tôi có thể sửa lỗi này bằng cách thay đổi một cái gì đó trong ứng dụng của chúng tôi hoặc bằng cách thêm các đối số JVM không?

Đó có phải là lỗi JDK không, tôi có nên báo cáo không?

cập nhật 2020-04-25:

Theo như tôi thấy thì các tệp nhật ký cũng chứa các bản ghi GC. Đây là nhật ký GC đầu tiên:

$ 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)
...

Thật không may, nó dường như không liên quan vì nó bắt đầu sau khi tạm dừng thứ ba.

cập nhật 2020-04-26:

Với OpenJDK 14, ứng dụng sử dụng 100% CPU trong máy VirtualBox (CPU đơn) của tôi (chạy trên CPU i7-6600U). Máy ảo có RAM 3,5 GB. Theo Trình quản lý tác vụ, 40% + là miễn phí và hoạt động của đĩa là 0% (tôi đoán điều này có nghĩa là không trao đổi). Thêm một CPU khác vào máy ảo (và cho phép siêu phân luồng cho các máy vật lý) làm cho ứng dụng đủ nhanh trở lại. Tôi chỉ tự hỏi, có phải đó là một sự đánh đổi có chủ ý trong quá trình phát triển JDK làm giảm hiệu năng trên các máy CPU đơn (hiếm) để làm cho JVM nhanh hơn trên các CPU đa luồng / siêu phân luồng?


3
-Xlog:all=debugbật đăng nhập GC? Đó sẽ là dự đoán đầu tiên của tôi cho bất kỳ tạm dừng.
kichik

Bạn đã thử chạy với một hồ sơ và so sánh kết quả? Tôi nghĩ đó sẽ là điều tự nhiên phải làm.
Axel

1
đồng thời kiểm tra các thông báo hệ thống cửa sổ, thử bản dựng khác cho jdk 14. Nếu vẫn thất bại, leo thang là một vấn đề?
Khanna111

1
@ Yan.F: OpenJDK 11 sẽ không được hỗ trợ mãi mãi, đã đến lúc chuẩn bị các bản phát hành và lỗi mới. Hơn nữa, có vẻ như lỗi JDK - có thể được sửa hoặc không nhưng cũng có thể giúp người khác. Dù sao, đối với tôi, nó chủ yếu là sự tò mò. Mặt khác, bây giờ tôi muốn nói với khách hàng những yêu cầu hệ thống tối thiểu của ứng dụng.
palacsint

1
@ Khanna111: Vâng, tôi vừa viết nó như một câu trả lời.
palacsint

Câu trả lời:


6

Từ kinh nghiệm của tôi, các vấn đề về hiệu năng với JDK có liên quan chủ yếu đến một trong những điều sau đây:

  • Biên soạn JIT
  • Cấu hình VM (kích thước heap)
  • Thuật toán GC
  • Các thay đổi trong JVM / JDK phá vỡ các ứng dụng đang chạy tốt đã biết
  • (Ồ, và tôi đã quên đề cập đến việc tải lớp ...)

Nếu bạn chỉ sử dụng cấu hình JVM mặc định kể từ OpenJDK11, có lẽ bạn nên đặt một số tùy chọn nổi bật hơn thành các giá trị cố định, như kích thước GC, Heap, v.v.

Có thể một số công cụ phân tích đồ họa có thể giúp theo dõi vấn đề của bạn. Giống như Retrace, AppDoperics hoặc FlightRecorder và những thứ tương tự. Chúng cung cấp tổng quan hơn về trạng thái tổng thể của heap, chu kỳ gc, RAM, luồng, tải CPU, v.v. tại một thời điểm nhất định so với các tệp nhật ký có thể cung cấp.

Tôi có hiểu chính xác rằng ứng dụng của bạn ghi khoảng 30710 dòng vào nhật ký trong giây đầu tiên chạy (theo OpenJDK11) không? Tại sao nó "chỉ" viết khoảng 7k dòng trong OpenJDK14 trong giây đầu tiên? Điều này có vẻ như là một sự khác biệt rất lớn đối với một ứng dụng chỉ mới bắt đầu trên các JVM khác nhau đối với tôi ... Bạn có chắc chắn không có ví dụ nào về các stacktraces ngoại lệ được đổ vào nhật ký không?
Các con số khác đôi khi còn cao hơn, vì vậy có thể sự chậm lại có liên quan đến đăng nhập ngoại lệ? Hoặc thậm chí hoán đổi, nếu RAM bị thấp?
Trên thực tế tôi đang nghĩ, nếu một ứng dụng không ghi bất cứ điều gì vào nhật ký, thì đây là dấu hiệu hoạt động trơn tru mà không gặp vấn đề gì (trừ khi nó bị đóng băng hoàn toàn trong thời gian này). Điều gì đang xảy ra từ giây 12-22 (trong trường hợp OpenJDK14 ở đây) là điều khiến tôi quan tâm hơn ... các dòng đăng nhập đi qua mái nhà ... tại sao ?
Và sau đó, việc đăng nhập giảm xuống tất cả các giá trị thấp trong khoảng 1-2k dòng ... lý do cho điều đó là gì ?? (vâng, có lẽ đó là gc đá vào thứ hai 22 và một tabula rasa giải quyết một số điều ...?)

Một điều nữa có thể là tuyên bố của bạn về các máy "CPU đơn". Có phải điều này cũng bao hàm "lõi đơn" (Idk, có thể phần mềm của bạn được tùy biến trên phần cứng cũ hoặc một cái gì đó)? Và máy ảo "CPU đơn" đang chạy trên các máy đó? Nhưng tôi cho rằng, tôi đã sai về những giả định này, vì hầu như tất cả các CPU đều là đa lõi ngày nay ... nhưng tôi sẽ điều tra về một vấn đề đa luồng (bế tắc) có thể.


2
Vui lòng không sử dụng chữ ký hoặc khẩu hiệu trong bài đăng của bạn, "GL và HF" lặp đi lặp lại được coi là tiếng ồn và làm mất tập trung từ nội dung bài đăng của bạn ở đây. Xem meta.stackexchange.com/help/behavior để biết thêm thông tin.
meagar

1
"Tôi có hiểu chính xác rằng ứng dụng của bạn ghi khoảng 30710 dòng vào nhật ký trong giây đầu tiên chạy (dưới OpenJDK11) không?" - Vâng bạn đã đúng.
palacsint

1
"Bạn có chắc chắn không có số lượng lớn các ngoại lệ stacktraces được đổ vào nhật ký không?" - Nhật ký sạch sẽ, tôi không tìm thấy gì lạ ở đó, ứng dụng hoạt động chính xác (ngoại trừ việc nó chạy rất chậm).
palacsint

1
GC đang đá ở giây thứ 22 và ứng dụng vẫn chậm sau đó. Tôi cũng đã cập nhật câu hỏi. Xin lưu ý rằng ứng dụng demo update4j cũng có vấn đề tương tự. Cảm ơn bạn đã trả lời!
palacsint

1
30k + dòng nhật ký trong một giây là khá lớn ... bạn không đồng ý chứ? Tôi thực sự tự hỏi những gì có thể hữu ích để được đăng nhập để chấp nhận số lượng dòng nhật ký cao này trong một thời gian ngắn như vậy ... Bạn đã thử tắt đăng nhập hoàn toàn và hồ sơ ứng dụng trong chế độ này chưa? (Tôi tò mò, nhưng có lẽ việc đăng nhập thực sự không có tác động như bạn ngụ ý với hành vi update4j)
Antares

5

Vì nó sử dụng 100% CPU "hầu hết thời gian" và phải mất 10 lần (!) Với Java 14, điều đó có nghĩa là bạn đang lãng phí 90% CPU của mình trong Java 14.

Hết dung lượng heap có thể làm điều đó, vì bạn dành toàn bộ thời gian cho GC, nhưng dường như bạn đã loại trừ điều đó.

Tôi nhận thấy rằng bạn đang điều chỉnh tùy chọn khóa thiên vị và nó tạo ra sự khác biệt đáng kể. Điều đó cho tôi biết rằng có thể chương trình của bạn thực hiện nhiều công việc đồng thời trong nhiều luồng. Có thể chương trình của bạn có một lỗi đồng thời xuất hiện trong Java 14, nhưng không phải trong Java 10. Điều đó cũng có thể giải thích tại sao việc thêm một CPU khác làm cho nó nhanh hơn gấp đôi.

Lỗi đồng thời thường chỉ hiển thị khi bạn không may mắn và trình kích hoạt thực sự có thể là bất cứ điều gì, như thay đổi đối với tổ chức hashmap, v.v.

Đầu tiên, nếu nó khả thi, hãy kiểm tra xem có bất kỳ vòng lặp nào có thể đang bận chờ đợi thay vì ngủ không.

Sau đó, chạy một trình lược tả trong chế độ lấy mẫu (jvisualvm sẽ làm) và tìm kiếm các phương thức chiếm% lớn hơn nhiều so với tổng thời gian cần thiết. Vì hiệu suất của bạn giảm đi 10 lần, nên mọi vấn đề trong đó sẽ thực sự xuất hiện.


Khóa thiên vị là cần thiết trong quá khứ nhưng hiện tại không quá nhiều và nó được đề xuất để tắt theo mặc định và sau đó bị xóa: openjdk.java.net/jeps/374
JohannesB

3

TL; DR : Đó là hồi quy OpenJDK.

Tôi không ngoại trừ điều đó nhưng tôi có thể tái tạo vấn đề bằng một thế giới xin chào đơn giản:

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

Tôi đã sử dụng hai tệp bó này:

main-1cpu.bat, giới hạn javaquá trình chỉ một CPU:

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, javaquá trình có thể sử dụng cả hai CPU:

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

(Sự khác biệt là affinitygiá trị và tên của tệp nhật ký. Tôi đã bọc nó để dễ đọc hơn nhưng có \thể không hoạt động trên Windows.)

Một vài phép đo trên Windows 10 x64 trong VirtualBox (có hai CPU):

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
...

Các tracelog được sản xuất có chứa các khoảng dừng tương tự mà bạn có thể thấy trong câu hỏi.

Chạy Mainkhông có tracelogs nhanh hơn nhưng vẫn có thể thấy sự khác biệt giữa phiên bản CPU đơn và CPU hai: ~ 4-7 giây so với ~ 400 ms.

Tôi đã gửi kết quả này đến danh sách thư hotspot-dev @ openjdk và các nhà phát triển ở đó đã xác nhận rằng đây là điều mà JDK có thể xử lý tốt hơn . Bạn cũng có thể tìm thấy các bản sửa lỗi trong luồng. Hy vọng nó sẽ được sửa trong OpenJDK 15.


2

Đây là một vấn đề thú vị và nó sẽ đòi hỏi một lượng nỗ lực không xác định để thu hẹp nó vì có nhiều hoán vị và kết hợp cần phải được thử và dữ liệu được thu thập và đối chiếu.

Có vẻ như đã không có giải pháp cho điều này trong một thời gian. Có lẽ điều này có thể cần phải được leo thang.

EDIT 2: Vì "ThreadLocalHandshakes" không được dùng nữa và chúng tôi có thể cho rằng việc khóa được dự kiến, nên đề nghị thử mà không sử dụng "UseBiasedLocking" để hy vọng tăng tốc kịch bản này.

Tuy nhiên, có một số đề xuất để thu thập thêm dữ liệu và cố gắng cô lập vấn đề.

  1. Phân bổ nhiều hơn một lõi [Tôi thấy rằng bạn đã thử nó và vấn đề biến mất. Có vẻ là một vấn đề với việc thực thi một luồng / s loại trừ những người khác. Xem số 7 dưới đây)
  2. Phân bổ nhiều đống hơn (có lẽ các yêu cầu của v14 nhiều hơn so với các jdks trước đó)
  3. Phân bổ thêm bộ nhớ cho Win 10 VB.
  4. Kiểm tra các thông báo hệ điều hành (Win 10 trong trường hợp của bạn)
  5. Chạy nó trong Win 10 không ảo hóa.
  6. Hãy thử bản dựng khác của jdk 14
  7. Thực hiện một luồng kết xuất mỗi (hoặc hồ sơ) vài khoảng thời gian. Phân tích những gì chủ đề đang chạy độc quyền. Có lẽ có một thiết lập để chia sẻ thời gian công bằng. Có lẽ có một chủ đề ưu tiên cao hơn đang chạy. Chủ đề đó là gì và nó đang làm gì? Trong linux, bạn có thể thống kê các tiến trình nhẹ (luồng) liên quan đến một tiến trình và trạng thái của nó trong thời gian thực. Một cái gì đó tương tự trên Win 10?
  8. Sử dụng CPU? 100% hay ít hơn? Bị ràng buộc bởi CPU hay mem? 100% CPU trong luồng dịch vụ? Chủ đề dịch vụ nào?
  9. Bạn đã thiết lập một thuật toán GC chưa?

Cá nhân tôi đã chứng kiến ​​các vấn đề trong các phiên bản có liên quan đến GC, thay đổi kích thước heap, các vấn đề với các thùng chứa ảo hóa, v.v.

Không có câu trả lời dễ dàng cho điều đó, tôi nghĩ, đặc biệt là vì câu hỏi này đã được một thời gian. Nhưng chúng ta có thể thử, tất cả những điều tốt nhất và cho chúng ta biết kết quả của một số bước cô lập này là gì.

EDIT 1: từ câu hỏi được cập nhật, nó dường như có liên quan đến một GC hoặc một chuỗi dịch vụ khác tiếp quản lõi đơn không công bằng (Bắt tay theo luồng cục bộ)?


Thêm lõi CPU bổ sung được sử dụng để kích hoạt chuyển đổi từ công thái học Java trên các hệ thống 32 bit từ máy khách sang lớp máy chủ vm với Trình biên dịch phân cấp và cấp độ khác nhau nếu đó vẫn là trường hợp có thể giải thích sự khác biệt đột ngột về hiệu suất và sử dụng bộ nhớ, vâng JVM hiệu suất rất phức tạp 😁
JohannesB

3
Công thái học Java (cài đặt mặc định) vẫn khác nhau đối với 1 CPU (ví dụ: -XX: + UseSerialGC) hoặc 2 CPU (ví dụ: G1GC, LoopStripMiningIter = 1000, ... ShortLoop = 100) Nhưng sau khi chắc chắn với -XX: + PrintFlagsFinal mà tôi đã điều chỉnh tất cả các tham số thành cùng một bản cập nhật đang chạy hoặc tương tự, vẫn khởi động rất chậm chỉ với một thay vì 2 CPU với cmd.exe / C start / affinity 0x1 (nhưng cực kỳ nhanh với 0x3 - do đó sử dụng 2 cpus (1 + 10 nhị phân)). Tôi xác nhận rằng chúng tôi không thể đổ lỗi cho bất kỳ trình thu gom rác nào bằng cách sử dụng Epsilon GC được thiết kế để tránh mọi chi phí hoạt động. Tuy nhiên, TieredCompilation được bật
JohannesB

Tôi hiểu rồi. Với Epsilon GC, dường như nó chậm như vậy. Trong trường hợp này, trạng thái luồng và kết xuất để đánh giá nơi nó bị kẹt có thể là một cách. Cả trong thế giới Java và thế giới hệ điều hành (linux nếu tôi nhớ là gcore)
Khanna111

1

Hãy cẩn thận với việc đăng nhập vào đĩa chậm, nó sẽ làm chậm ứng dụng của bạn:

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

Nhưng nó dường như không phải là nguyên nhân của vấn đề vì CPU vẫn đang bận và bạn không phải đợi tất cả các luồng đến điểm an toàn nhờ bắt tay luồng cục bộ: https: // openjdk. java.net/jeps/312

Cũng không liên quan trực tiếp đến vấn đề bạn gặp phải nhưng nhìn chung hơn nếu bạn muốn cố gắng tăng hiệu năng ra khỏi phần cứng của mình trong thời gian khởi động, hãy xem AppCDS (chia sẻ dữ liệu lớp):

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

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.