8

Tôi có một ứng dụng máy chủ, trong những trường hợp hiếm hoi, có thể phân bổ một lượng lớn bộ nhớ.Buộc thu gom rác đầy đủ khi chiếm đóng bộ nhớ vượt quá ngưỡng nhất định

Nó không phải là một rò rỉ bộ nhớ, như những khối có thể được yêu cầu bồi thường trở lại bởi các bộ thu rác bằng cách thực hiện một bộ sưu tập rác đầy đủ. Bộ sưu tập rác bình thường giải phóng lượng bộ nhớ quá nhỏ: không đủ trong ngữ cảnh này.

Bộ thu gom rác thực hiện các GC đầy đủ này khi thấy phù hợp, cụ thể là khi dấu chân bộ nhớ của ứng dụng gần mức tối đa được chỉ định với -Xmx.

Đó sẽ là ok, nếu nó không được cho thực tế là những vấn đề cấp phát bộ nhớ đến trong bursts, và có thể gây OutOfMemoryErrors do thực tế rằng JVM không có khả năng để thực hiện một GC đủ nhanh để giải phóng bộ nhớ cần thiết. Nếu trước đó tôi gọi System.gc() theo cách thủ công, tôi có thể ngăn chặn tình huống này.

Dù sao, tôi không muốn theo dõi phân bổ bộ nhớ của jvm của mình (hoặc chèn quản lý bộ nhớ vào logic của ứng dụng của tôi); nó sẽ là tốt đẹp nếu có một cách để chạy máy ảo với một ngưỡng bộ nhớ, trên đó GC đầy đủ sẽ được thực hiện tự động, để phát hành rất sớm bộ nhớ tôi sẽ cần.

Câu chuyện dài: Tôi cần một cách (tùy chọn dòng lệnh?) Để định cấu hình jvm để phát hành sớm một lượng bộ nhớ tốt (nghĩa là thực hiện GC đầy đủ) khi bộ nhớ chiếm đến một ngưỡng nhất định, tôi không 't quan tâm nếu điều này làm chậm ứng dụng của tôi xuống mỗi một lần trong một thời gian.

Tất cả những gì tôi đã tìm thấy cho đến bây giờ là những cách để thay đổi kích thước của các thế hệ, nhưng đó không phải là những gì tôi cần (ít nhất là không trực tiếp).

Tôi đánh giá cao đề xuất của bạn,

Silvio

T.B. Tôi đang làm việc trên một cách để tránh phân bổ lớn, nhưng nó có thể đòi hỏi một thời gian dài và khi đó ứng dụng của tôi cần một sự ổn định ít

CẬP NHẬT: phân tích các ứng dụng với jvisualvm, tôi có thể thấy rằng vấn đề là ở thế hệ cũ

Trả lời

6

Từ here (đây là một trang 1.4.2, nhưng cùng một lựa chọn nên tồn tại trong tất cả các Sun JVM):

giả sử bạn đang sử dụng các bộ thu rác CMS (mà tôi tin rằng các máy chủ bật theo mặc định), tùy chọn bạn muốn là

-XX:CMSInitiatingOccupancyFraction=<percent> 

trong đó% là% bộ nhớ đang dùng sẽ kích hoạt GC đầy đủ.

Chèn tuyên bố từ chối trách nhiệm tiêu chuẩn ở đây làm rối loạn các thông số GC có thể cung cấp cho bạn các vấn đề về hiệu suất nghiêm trọng, thay đổi cực kỳ theo máy, v.v.

0

Hãy thử sử dụng tùy chọn máy chủ. Nó sẽ cho phép gc song song và bạn sẽ có một số tăng hiệu suất nếu bạn sử dụng bộ xử lý đa lõi.

+0

Tôi đã sử dụng nó –

0

Bạn đã thử chơi với G1 gc chưa? Nó sẽ có sẵn trong 1.6.0u14 trở đi.

1

Bạn có biết bể thu gom rác nào đang phát triển quá lớn không? .... nghĩa là. eden vs không gian sống sót? (thử tùy chọn JVM -Xloggc:<file> log GC status to a file with time stamps) ... Khi bạn biết điều này, bạn sẽ có thể điều chỉnh kích thước của hồ bơi được thực hiện bằng một trong các tùy chọn được đề cập tại đây: hotspot options for Java 1.4

Tôi biết trang đó dành cho 1,4 JVM, Tôi dường như không thể tìm thấy cùng các tùy chọn -X trong các tùy chọn trợ giúp cài đặt 1.6 hiện tại của tôi, trừ khi đặt các kích thước nhóm cá nhân đó là một tính năng phi tiêu chuẩn, không chuẩn!

+0

vấn đề chắc chắn là thế hệ cũ, như đã thấy với jvisualvm –

1

Có một giải thích rất chi tiết về cách GC hoạt động here và nó liệt kê các tham số để kiểm soát bộ nhớ có sẵn cho các nhóm bộ nhớ khác nhau/thế hệ.

+1

plz cập nhật liên kết hoặc xóa câu trả lời. cám ơn. – user1050755

+0

Cảm ơn nhận xét, liên kết đã được cập nhật. –

3

Khi bạn phân bổ các đối tượng lớn không vừa với thế hệ trẻ, chúng sẽ được phân bổ ngay lập tức trong không gian thế hệ đã thuê. Không gian này chỉ được GC'ed khi một GC đầy đủ được chạy mà bạn cố gắng để buộc.

Tuy nhiên tôi không chắc chắn điều này sẽ giải quyết được sự cố của bạn. Bạn nói "JVM không thể thực hiện một GC đủ nhanh". Ngay cả khi phân bổ của bạn đến trong bursts, mỗi phân bổ sẽ gây ra VM để kiểm tra xem nó có đủ không gian có sẵn để làm điều đó. Nếu không - và nếu đối tượng quá lớn đối với thế hệ trẻ - nó sẽ gây ra một GC đầy đủ mà nên "ngăn chặn thế giới", do đó ngăn chặn phân bổ mới diễn ra ở nơi đầu tiên. Khi GC hoàn tất, đối tượng mới của bạn sẽ được cấp phát.

Nếu ngay sau đó yêu cầu phân bổ lớn thứ hai được yêu cầu trong cụm từ của bạn, nó sẽ làm điều tương tự một lần nữa. Tùy thuộc vào việc các đối tượng ban đầu là vẫn cần thiết, nó hoặc là sẽ có thể thành công trong GC'ing nó, do đó làm cho phòng cho việc phân bổ tiếp theo, hoặc thất bại nếu dụ đầu tiên vẫn còn tham chiếu.

Bạn nói "Tôi cần một cách [...] để phát hành sớm một lượng bộ nhớ tốt (ví dụ: thực hiện GC đầy đủ) khi chiếm đóng bộ nhớ đạt đến một ngưỡng nhất định". Điều này theo định nghĩa chỉ có thể thành công, nếu đó "số lượng tốt của bộ nhớ" không được tham chiếu bởi bất cứ điều gì trong ứng dụng của bạn nữa.

Từ những gì tôi hiểu ở đây, bạn có thể có điều kiện chủng tộc đôi khi bạn có thể tránh bằng cách xen kẽ các yêu cầu GC thủ công. Nói chung, bạn không bao giờ phải lo lắng về những điều này - từ kinh nghiệm của tôi, OutOfMemoryError chỉ xảy ra nếu có quá nhiều phân bổ để phù hợp với vùng heap đồng thời. Trong tất cả các tình huống khác, vấn đề "duy nhất" phải là sự xuống cấp hiệu suất (có thể trở nên cực đoan, tùy thuộc vào hoàn cảnh, nhưng đây là một vấn đề khác).

Tôi khuyên bạn nên phân tích sâu hơn về vấn đề chính xác để loại trừ điều này. Tôi khuyên bạn nên sử dụng công cụ VisualVM đi kèm với Java 6. Khởi động nó và cài đặt plugin VisualGC. Điều này sẽ cho phép bạn xem các thế hệ bộ nhớ khác nhau và kích thước của chúng. Ngoài ra còn có rất nhiều tùy chọn ghi nhật ký liên quan đến GC, tùy thuộc vào VM bạn sử dụng. Một số tùy chọn đã được đề cập trong các câu trả lời khác.

Các tùy chọn khác để chọn GC sử dụng và cách tinh chỉnh ngưỡng không quan trọng trong trường hợp của bạn, vì tất cả đều phụ thuộc vào đủ bộ nhớ để chứa tất cả các đối tượng mà ứng dụng của bạn cần tại bất kỳ thời điểm nào. Các tùy chọn này có thể hữu ích nếu bạn có vấn đề về hiệu năng liên quan đến hoạt động GC nặng, nhưng tôi lo sợ chúng sẽ không dẫn đến giải pháp trong trường hợp cụ thể của bạn.

Khi bạn tự tin hơn vào những gì đang thực sự xảy ra, việc tìm kiếm giải pháp sẽ trở nên dễ dàng hơn.

+0

Vâng, tôi tin rằng đó là một điều kiện chủng tộc. Tôi nghĩ rằng những gì xảy ra là như sau: ứng dụng của tôi nhận được nhiều yêu cầu cấp phát bộ nhớ, làm chậm các chủ đề cần bộ nhớ. Mặc dù các luồng này đang hoạt động nhưng chúng không thể giải phóng bất cứ thứ gì, vì vậy chúng giữ các phần bộ nhớ, trong khi đó, một bộ sưu tập rác được kích hoạt làm chậm hệ thống xuống, do đó ngăn các luồng khác giải phóng bộ nhớ trong một vòng luẩn quẩn. –

1

Các JVM chỉ phải ném một OutOfMemoryErrorsau nó đã cố gắng để giải phóng bộ nhớ thông qua thu gom rác thải (theo cả hai the API docs for OutOfMemoryErrorthe JVM specification). Do đó, những nỗ lực của bạn để buộc thu gom rác thải sẽ không tạo ra bất kỳ sự khác biệt nào. Vì vậy, có thể có một cái gì đó quan trọng hơn đang xảy ra ở đây - hoặc là một vấn đề với chương trình của bạn không đúng cách xóa tài liệu tham khảo hoặc, ít có khả năng, một lỗi JVM.

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