2009-07-18 43 views
8

Tôi có một đoạn mã tải một hình ảnh rất lớn trong bộ nhớ. Vì vậy, có vẻ như một điều hợp lý để gọiKhi nào để thu gom rác

System.gc(); 

trước khi tải hình ảnh. Từ những gì tôi có thể nói nó hoạt động mà không có vấn đề gì.

Hôm qua tôi quyết định sử dụng phần mềm khá hữu ích có tên là FindBugs để quét mã của bạn và báo cáo lại các sự cố có thể gây ra lỗi hoặc chiến lược thường không được thông báo. Vấn đề là đoạn mã tôi đề cập này được báo cáo. Mô tả là:

... buộc thu gom rác; cực kỳ mơ hồ trừ đang chuẩn

Và nó tiếp tục xây dựng:

Mã dứt khoát gọi rác bộ sưu tập. Ngoại trừ việc sử dụng cụ thể trong các tiêu chuẩn , điều này rất đáng ngờ.

Trong quá khứ, tình huống mà người đã viện dẫn một cách rõ ràng các bộ thu rác trong thói quen như phương pháp Finalize gần hoặc đã dẫn đến lỗ đen hiệu suất lớn. Rác bộ sưu tập có thể tốn kém. Mọi tình huống buộc hàng trăm hoặc hàng nghìn bộ sưu tập rác sẽ khiến máy thu thập thông tin.

Vì vậy, câu hỏi của tôi là: KHÔNG ĐƯỢC lập trình gọi bộ gom rác trong một trường hợp như vậy? Mã của tôi chỉ gọi nó một lần và phương thức mà nó được sử dụng hiếm khi được sử dụng. Và nếu bạn không thể gọi nó thì bạn nên làm gì trong trường hợp bạn cần nhiều bộ nhớ nhất có thể trước khi thực hiện một thao tác tốn nhiều bộ nhớ và bạn cần giải phóng bộ nhớ nhiều như trước khi nó hoạt động?

+1

Trong trường hợp này, bạn có thể là hoạt động nối tiếp. Nếu bạn cho phép GC quyết định thời điểm chạy, nó có thể chạy tốt khi ứng dụng đang chặn I/O. –

+0

Q: Khi nào nên gọi System.gc(). A: không bao giờ – KitsuneYMG

+1

wow đó là cái nhìn sâu sắc đầy đủ. Tôi hoàn toàn hiểu tại sao tôi không bao giờ nên gọi gc bằng câu trả lời của bạn. Cảm ơn nhiều. –

Trả lời

9

Bạn có nhận được bất kỳ cải tiến hiệu suất nào với System.gc() không? Tôi không nghĩ như vậy, vì bạn có thể không có nhiều đối tượng cần được thu thập trước khi bạn tải hình ảnh.

Thông thường người thu gom rác hiện đại biết rõ nhất khi nào chạy, vì vậy bạn không nên ép buộc một bộ sưu tập, trừ khi bạn có lý do thực sự tốt. (ví dụ như một ứng dụng đo điểm chuẩn theo đề xuất của plugin đó)

btw: Gọi System.gc() khuyến nghị máy ảo thực hiện bộ sưu tập "đầy đủ" hoặc "lớn", nghĩa là tất cả các chuỗi được dừng ngay. Nếu không, nó có thể sẽ chỉ làm cho bộ sưu tập rác "nhỏ", mà không dừng lại tất cả các chủ đề.

Chạy chương trình của bạn với -verbose: gc để xem có bao nhiêu byte được thu thập.

Ngoài ra còn có rất nhiều thông tin kỹ thuật về thu gom rác thải ở đây: http://java.sun.com/developer/technicalArticles/Programming/GCPortal/

+4

System.gc() không "ép buộc" bất cứ thứ gì. VM là miễn phí để bỏ qua nó. Các từ ngữ trong Javadoc là "Gọi phương pháp gc * cho thấy * rằng Java Virtual Machine nỗ lực để tái chế các đối tượng không sử dụng" (nhấn mạnh mỏ) –

+2

-1 cho FAILING để đọc javadoc trên System.gc() như Adrian cho biết, nó lực lượng không có gì. http://stackoverflow.com/questions/1147511/how-can-i-estimate-amount-of-memory-left-with-calling-system-gc/1149182#1149182 vì thực sự buộc gc – KitsuneYMG

1

Thật tuyệt khi gọi cho người thu gom rác, bạn không gặp phải bất kỳ "vấn đề" nào từ nó. Tuy nhiên, tôi nghi ngờ nó sẽ có hiệu quả tăng hiệu suất, trừ khi cuộc gọi đó cũng đề với defragging dữ liệu được phân bổ. Tôi không biết điều đó.

Điều bạn nên làm trong trường hợp này là cấu hình mã. Chạy nó nhiều lần, xem loại kết quả bạn nhận được.

9

Thông thường GC là thông minh hơn bạn, vì vậy tốt hơn nên để nó chạy bất cứ khi nào thời gian chạy quyết định. Nếu thời gian chạy cần bộ nhớ, nó sẽ chạy chính GC

+1

Vấn đề là điều này chỉ sau khi nó cố gắng phân bổ một cái gì đó. Nếu bạn đang ở trong một tình huống mà bạn "biết" rằng bạn có một bố trí bộ nhớ rất không tổ chức và bạn "biết" bạn sắp yêu cầu một khối bộ nhớ lớn, bạn có thể chỉ cần gọi GC một vài hướng dẫn trước đó. –

+2

Bạn không bao giờ "biết" chắc chắn rằng bạn có bố cục bộ nhớ không được sắp xếp. GC có thể chỉ chạy, cho tất cả các bạn biết. Phần "đánh dấu" của đánh dấu và quét lấy tài nguyên và thời gian ngay cả khi bạn không thu thập bất kỳ thứ gì.Đó là lý do tại sao nó gần như luôn luôn là một trường hợp vi phạm tiêu cực ròng hoặc (trường hợp tốt nhất) để thử và outsmart GC. – Jason

+0

Thời gian chạy và gc là miễn phí để thay đổi và di chuyển xung quanh các đối tượng trong bộ nhớ bất cứ khi nào nó cảm thấy như nó (đối tượng giống như một con trỏ đến một con trỏ nếu bạn đến từ thế giới C), bạn sẽ khó bao giờ "biết" mà bạn có một bố cục không tổ chức. – nos

1

Thông thường, bạn không nên can thiệp vào bộ thu gom rác. Nếu nó cần thiết để giải phóng bộ nhớ trước khi tải hình ảnh, thì bộ thu gom rác sẽ làm điều đó cho bạn.

Bất kể, nếu bạn chỉ làm điều đó một lần, điều đó có thể sẽ không ảnh hưởng đến hiệu suất của bạn một cách mạnh mẽ. Mọi thứ được thực hiện trong các vòng lặp quan trọng hơn rất nhiều.

1

Bạn đã có rất nhiều lời khuyên tốt, mà tôi sẽ cố gắng không nhắc lại.

Nếu bạn thực sự gặp sự cố với GC, chẳng hạn như toàn bộ các ứng dụng của bạn trong một giây, hãy thực hiện như sau: 1. kiểm tra xem không có bất kỳ lệnh gọi nào tới System.gc(); 2. kiểm tra các tùy chọn khác nhau để định cấu hình gc. Có rất nhiều những người xung quanh, và họ có nhiều hữu ích hơn, sau đó buộc gc.

1

Đảm bảo rằng các đối tượng lớn có thể được gc'ed càng sớm càng tốt. I E. đặt biến thành null và/hoặc để chúng rơi ra khỏi phạm vi. Điều này có ích!

0

Nói chung, không. Nó không thích hợp để gọi System.gc(). Tuy nhiên, tôi đã có một vài trường hợp mà nó có ý nghĩa.

Trong phần mềm tôi viết, có một lớp theo dõi hiệu suất được tích hợp sẵn. Nó chủ yếu được sử dụng trong quá trình kiểm tra tự động, nhưng có thể được sử dụng trong trường cho mục đích chẩn đoán. Giữa các thử nghiệm hoặc sau khi chạy cụ thể, chúng tôi sẽ gọi System.gc một vài lần và sau đó ghi lại bộ nhớ vẫn còn hiện diện. Nó cung cấp cho chúng tôi một tiêu chuẩn in chân bộ nhớ cơ bản để xem các đường xu hướng tiêu thụ bộ nhớ theo thời gian. Trong khi điều này có thể được thực hiện với một số giao diện JVM bên ngoài, thì việc thực hiện nó tại chỗ và số chính xác không dễ dàng hơn.

Trên một hệ thống cũ hơn nhiều, chúng tôi có thể có tối đa 72 JVM riêng biệt (vâng, 72, đã có lý do chính đáng cho nó tại thời điểm xây dựng). Trong hệ thống đó, để lại heap miễn phí trôi nổi trên tất cả 72 JVM có thể mang lại một số tiêu thụ bộ nhớ quá mức (vượt quá bộ nhớ vật lý). System.gc() được gọi giữa các bài tập dữ liệu nặng để cố gắng giữ JVM gần với mức trung bình để giữ cho vùng heap không phát triển (giới hạn heap có thể là một hướng khác, nhưng sau đó nó sẽ yêu cầu người triển khai định cấu hình nhiều hơn cho mỗi trang web và ý thức hơn về những gì đã xảy ra dưới mui xe để làm cho nó đúng và không có hệ thống không tải được).

1

Nếu phân bổ bộ nhớ không thành công, chu kỳ GC được bắt đầu và phân bổ lại được thử lại.