2015-04-20 24 views
16

Tôi có một chương trình java mà là một thuật toán máy học điển hình, cập nhật các giá trị cho một số thông số của một số phương trình:chương trình Java là nhận được chậm hơn sau khi chạy một thời gian

for (int iter=0; iter<1000; iter++) { 
    // 1. Create many temporary variables and do some computations       
    // 2. Update the value for the parameters      
} 

Các tính toán của việc cập nhật các thông số khá phức tạp, và tôi phải tạo ra nhiều đối tượng tạm thời, nhưng chúng không được tham chiếu trong vòng lặp. Các mã trong vòng lặp là CPU chuyên sâu, và không truy cập đĩa. Chương trình này tải một tập dữ liệu tương đối lớn, do đó, tôi đã cấp bộ nhớ 10G (-Xmx10G) cho JVM, lớn hơn nhiều so với yêu cầu (đỉnh tại ~ 6G bằng lệnh "trên cùng" hoặc trình quản lý tác vụ của cửa sổ).

Tôi đã thử nghiệm trên một số máy linux (centos 6, bộ nhớ 24G) và máy cửa sổ (win7, 12G), cả hai đều có cài đặt SUN Hotspot JDK/JRE 1.8. Tôi đã không chỉ định các tham số JVM khác ngoại trừ -Xmx. Cả hai máy đều dành riêng cho chương trình của tôi.

Trên các cửa sổ, chương trình của tôi chạy tốt: mỗi lần lặp lại sử dụng thời gian chạy rất giống nhau. Tuy nhiên, thời gian chạy trên tất cả các máy centos là lạ. Ban đầu nó chạy đúng, nhưng chậm lại đáng kể (~ 10 lần chậm hơn) ở lần lặp thứ 7/thứ 8, và sau đó giữ chậm ~ 10% trong mỗi lần lặp lại sau đó.

Tôi nghi ngờ nó có thể do trình thu gom rác của Java gây ra. Vì vậy, tôi sử dụng jconsole để theo dõi chương trình của tôi. Nhỏ GC xảy ra rất thường xuyên trên cả hai máy, đó là bởi vì chương trình tạo ra nhiều biến tạm thời trong vòng lặp. Hơn nữa, tôi sử dụng "jstat -gcutil $ pid $ 1s" lệnh và bắt giữ số liệu thống kê:

Centos: https://www.dropbox.com/s/ioz7ai6i1h57eoo/jstat.png?dl=0

Window: https://www.dropbox.com/s/3uxb7ltbx9kpm9l/jstat-winpng.png?dl=0

[Sửa] Tuy nhiên, số liệu thống kê trên hai loại máy móc khác rất nhiều:

  1. "S1” trên cửa sổ nhảy nhanh từ 0 đến 50, trong khi thời gian lưu trú tại '0,00' trên centos
  2. 'E' trên cửa sổ thay đổi rất nhanh từ 0 đến 100. Như tôi pr. int stat cho mỗi giây, ảnh chụp màn hình không hiển thị tăng của nó đến 100. Trên centos, tuy nhiên, "E" tăng khá chậm về phía 100, và sau đó giảm xuống 0, và tăng trở lại.

Có vẻ như hành vi kỳ lạ của chương trình của tôi là do Java GC? Tôi mới dùng màn hình hiệu suất Java và không có ý tưởng tốt để tối ưu hóa cài đặt tham số GC. Bạn có đề nghị nào không? Cảm ơn nhiều!

+1

Bạn có chắc chắn phải tạo nhiều đối tượng "tạm thời" trong vòng lặp không? Nếu bạn có thể kéo một số người trong số họ ra khỏi vòng lặp và tái sử dụng các trường hợp tương tự trong mỗi lần lặp lại, nó sẽ tiết kiệm một số cho rất nhiều rác (bộ sưu tập), – JimmyB

+0

Tôi không thể di chuyển chúng ra khỏi vòng lặp. Lý do là chúng được sử dụng để lưu trữ các giá trị tạm thời cho phép tính toán học phức tạp. –

+0

Nếu bạn không sử dụng các đối tượng bất biến, bạn thường có thể thay đổi các giá trị được lưu trữ bên trong chúng ('setX (...)', ...) mà không cần tạo một đối tượng mới. – JimmyB

Trả lời

1

Tôi xin lỗi để đăng bài này như một câu trả lời nhưng tôi không có đủ số điểm để bình luận.

Nếu bạn nghĩ rằng đó là một vấn đề liên quan đến GC tôi muốn thay đổi nó cho Garbage Collector 1 -XX: + UseG1GC

tôi thấy giải thích ngắn gọn này về nó: http://blog.takipi.com/garbage-collectors-serial-vs-parallel-vs-cms-vs-the-g1-and-whats-new-in-java-8/

Bạn có thể chạy phần mềm của bạn dưới hồ sơ? Hãy thử sử dụng jprofiler, VisualVM hoặc thậm chí là profiler netbeans. Nó có thể giúp bạn rất nhiều.

tôi nhận thấy rằng bạn có đóng gói riêng của bạn về một vector và ma trận. lẽ bạn đang dành bộ nhớ nhiều hơn cần thiết với điều đó quá.Nhưng tôi không nghĩ đó là vấn đề.

Xin lỗi một lần nữa về việc không đóng góp làm nhận xét. (Nó sẽ là thích hợp hơn)

0

tôi sẽ xem xét tuyên bố vars bên ngoài vòng lặp phân bổ để mem được thực hiện một lần và loại bỏ GC hoàn toàn.

+0

(bao gồm tất cả/bất kỳ temp nhiệt độ nào bạn cần) – Syntax

1

Cho Java (hoặc bất kỳ ngôn ngữ thu gom rác) nào quá nhiều bộ nhớ có ảnh hưởng xấu đến hiệu suất. Các đối tượng trực tiếp (tham chiếu) trở nên thưa thớt tăng lên trong bộ nhớ dẫn đến việc tìm nạp thường xuyên hơn từ bộ nhớ chính. Lưu ý rằng trong các ví dụ bạn đã cho chúng tôi thấy các cửa sổ nhanh hơn đang thực hiện nhanh hơn toàn bộ GC hơn Linux - nhưng các chu trình GC (đặc biệt là các gcs đầy đủ) thường không tốt cho hiệu suất.

Nếu chạy tập huấn luyện không mất một thời gian đặc biệt dài, sau đó thử benchmark tại cấp phát bộ nhớ khác nhau.

Một giải pháp triệt để hơn, nhưng một trong đó nên có ảnh hưởng lớn là để loại bỏ (hoặc giảm càng nhiều càng tốt) tạo đối tượng trong vòng lặp bằng cách tái chế các đối tượng trong hồ bơi.

+0

Điều này nghe có vẻ tốt, đặc biệt vì có một bước nhảy đột ngột lớn trong thời gian thực hiện tại một thời điểm: âm thanh như thổi qua giới hạn kích thước bộ nhớ cache cho dữ liệu nóng của bạn không lưu toàn bộ bộ nhớ trong bộ nhớ cache. Có lẽ một hệ thống profiler sẽ có thể xác nhận điều đó. –

0

Trước tiên, thực hành tốt nhất là phổ biến để khai báo Biến ngoài vòng lặp để tránh thu thập garbace. như 'Wagner Tsuchiya' đã nói, hãy thử chạy một hồ sơ nếu bạn có nghi ngờ về GC. Nếu bạn muốn một số lời khuyên về điều chỉnh GC, tôi thấy đẹp blogpost.

0

Bạn có thể thử gọi System.gc() mỗi vài lần lặp để xem hiệu suất đi lên hoặc xuống. Điều này có thể giúp bạn thu hẹp nó xuống một số chẩn đoán câu trả lời trước đó.

0

Nếu thời gian GC là hàng trăm mili giây như trong ảnh chụp màn hình của bạn sau đó GC có thể không phải là vấn đề ở đây. Tôi đề nghị bạn nhìn vào tranh chấp khóa và có thể IO bằng cách sử dụng một profiler (Netbeans là tuyệt vời). Tôi biết bạn đã nói chương trình của bạn đã làm rất ít IO nhưng với hồ sơ (giống như gỡ lỗi), bạn phải loại bỏ tất cả các giả định của bạn và đi từng bước.

0

Theo kinh nghiệm của tôi, JAVA cần đủ bộ nhớ và 2 CPU trở lên. Nếu không, việc sử dụng CPU sẽ rất rộng khi GC bắt đầu chạy.

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