2013-01-09 34 views
11

Chúng tôi đang gặp phải một số vấn đề về hiệu suất JVM lạ.Tại sao java.lang.Object.getClass() (và phản chiếu) chậm hơn bình thường?

Chúng tôi có thành phần GUI lớn và hơi mờ (Actuate Formula 1 spreadsheet).

Nếu chúng ta khởi tạo tất cả từ Chủ đề sự kiện (như bạn nên), chúng tôi thấy rằng mã chạy chậm hơn nhiều (kéo chuột để chọn ô, có độ trễ đáng chú ý).

Nếu chúng ta khởi tạo nó lần đầu tiên trong chuỗi trình khởi chạy chính, và chỉ sau đó bắt đầu sử dụng nó trong EDT, nó chạy nhanh hơn rất nhiều.

Khi tôi nhìn vào lý do tại sao nó được thực hiện dần dần sử dụng một hồ sơ, các cuộc gọi phương pháp đó đang dùng tất cả thời gian là:

  • java.lang.Object.getClass()
  • java.lang .reflect.Array.newInstance (class, int)
  • java.lang.Class.getComponentType()
  • java.lang.Thread.currentThread()

Chúng tôi sử dụng 64-bit Sun Hotspot JVM trên Windows 7 (phiên bản đi kèm với JDK).

Có ai biết lý do nào khiến các phương pháp trên có thể hoạt động chậm hơn bình thường không?

Tôi nghĩ rằng có lẽ nó có liên quan đến thứ tự các lớp được tải .... là một lý thuyết hợp lý? Có ai biết về bất kỳ cách nào khác mà tôi có thể chẩn đoán tại sao các cuộc gọi phương thức này có thể mất nhiều thời gian không?

Tôi đã đính kèm hai ảnh chụp màn hình từ trình thu thập thông tin. Trong cả hai, tất cả những gì tôi đã làm là kéo chuột quanh các ô bảng tính trong khi profiler đang chạy. Vì vậy, nó chỉ cập nhật thành phần GUI và không làm được gì nhiều.

Cách đầu tiên là dành nhiều thời gian trong một phương thức có tên là "releaseLock()". Vì một số lý do, việc này mất nhiều thời gian vì "getComponentType()" mất nhiều thời gian hơn bình thường.

releaseLock

Điều thứ hai là sau khi tôi đã làm một "hack" để loại bỏ các chi phí "releaseLock()" - nhưng bây giờ nó chỉ dành rất nhiều thời gian trong "getLock()" do getClass() và currentThread() dùng lâu hơn so với bình thường:

getLock

Nhưng điều quan trọng là nếu tôi chỉ đơn giản là thay đổi thứ tự trong đó các mã được khởi tạo, không ai trong số mã này mất rất nhiều thời gian để thực hiện (nó doesn thậm chí không hiển thị trong hồ sơ ở tất cả).

Nếu tôi đã tối ưu hóa getLock(), ứng dụng vẫn hoạt động chậm hơn nhiều. Vấn đề thực sự có vẻ là các phương thức như getClass() mất quá nhiều thời gian. Không có cách nào để bù đắp cho điều này - getClass() được gọi ở quá nhiều nơi!

Sự khác biệt hiệu suất đáng chú ý ngay cả khi không có trình chạy hồ sơ.

Cũng xin nhớ rằng chúng tôi không thể thay đổi bất kỳ mã nào trong số này - đó là thành phần bên ngoài. Thách thức là giải thích tại sao mã thực thi chậm hơn rất nhiều trong một số trường hợp so với các trường hợp khác.

+1

Bạn có thể đăng ảnh chụp màn hình hồ sơ không? Ngoài ra, hồ sơ có thể có tác động đáng kể đến thời gian chạy. Bạn có thể loại trừ các phương pháp đó khỏi hồ sơ và xem liệu có những lý do nào khác cho sự chậm trễ của bạn không? – jlordo

+0

Tôi không biết cách loại trừ các phương thức này khỏi cấu hình nhưng bạn có thể thấy nó sử dụng lấy mẫu và hiển thị bảng phân tích. Tôi nghĩ những gì profiler được hiển thị là hợp lệ - nó không phải là mã khác nhau đang thực hiện, đơn giản là, vì lý do nào đó, các phương thức này thường khá rẻ (Object.getClass()) hiện đang mất nhiều thời gian. –

+1

Kết quả này có phù hợp không? Bởi vì nếu nó chỉ xảy ra một lần, sau đó nó có thể dễ dàng là một vấn đề lấy mẫu ("may mắn" trong việc lựa chọn khi lấy mẫu). –

Trả lời

1

Bạn có thể thử thực hiện một số hỗn hợp (java + nguyên bản) jstack -m các luồng của ứng dụng trong tải.

Điều này có thể sẽ đưa ra một số gợi ý về những gì đang xảy ra dưới sự che chở của Object.getClass().

Xem thêm If profiler is not the answer, what other choices do we have?.

Ngoài ra, hãy xem What does thread dump looks like when JVM spent time in GC. Nguyên nhân các bãi luồng JVM thông thường có thể không phải lúc nào cũng chính xác hoàn toàn vì chúng chỉ xảy ra trên safepoints.

Các vấn đề liên quan