Làm cách nào để buộc thu gom rác trong Java?


225

Có thể buộc thu gom rác trong Java, ngay cả khi nó khó thực hiện không? Tôi biết về System.gc();Runtime.gc();nhưng họ chỉ đề nghị làm GC. Làm thế nào tôi có thể buộc GC?


30
Có lẽ nó sẽ hữu ích để cung cấp một số nền tảng cho lý do tại sao bạn cần phải buộc GC. Thông thường trong một ngôn ngữ được thu gom rác, việc gọi một cách rõ ràng là gọi cho người thu gom.
Justin Ethier

3
Một JVM đã cho có thể cung cấp một số phương thức thu gom rác, mỗi phương thức đều có ưu điểm và nhược điểm riêng và thường có thể tránh được một tình huống cụ thể bằng cách gợi ý JVM khi khởi động. Xin hãy giải thích về kịch bản.
Thorbjørn Ravn Andersen

3
jmap -histo: live <pid> stackoverflow.com/questions/6418089/

5
Đây là trường hợp sử dụng để buộc thu gom rác: Tôi có một máy chủ với một đống 30 GB, trong đó ~ 12 GB thường được sử dụng (~ 5 triệu đối tượng). Cứ sau 5 phút, máy chủ dành khoảng một phút để thực hiện một nhiệm vụ phức tạp, trong đó khoảng 35 triệu đối tượng bổ sung được sử dụng. Một GC đầy đủ được kích hoạt một vài lần mỗi giờ, luôn luôn thay đổi trong nhiệm vụ phức tạp và đóng băng VM trong 10 đến 15 giây. Tôi rất thích buộc toàn bộ GC chạy vào thời điểm mà tác vụ phức tạp không chạy; sau đó sẽ tung hứng các đối tượng sống 5M chứ không phải 40M.
Steve

3
@JustinEthier Có một trường hợp khá rõ ràng khi bạn có thể muốn buộc GC, đó là đơn vị kiểm tra bất kỳ hành vi nào liên quan đến hệ thống phân cấp loại java.lang.ref.Reference.
Elias Vasylenko

Câu trả lời:


168

Tùy chọn tốt nhất của bạn là gọi System.gc()đơn giản là một gợi ý cho trình thu gom rác mà bạn muốn nó thực hiện một bộ sưu tập. Không có cách nào để buộc và thu gom ngay lập tức vì bộ thu gom rác là không xác định.


28
Nên có. non-deterministic == trouble
Pacerier

7
Một người thu gom rác có thể không xác định và vẫn cung cấp một cách để buộc một bộ sưu tập ngay lập tức. Ví dụ, thông thường trình thu thập .NET là không xác định nhưng một lệnh gọi tới GC.Collect () buộc nó chạy. Chỉ là Java chọn không phơi bày chức năng này.
Petr Hudeček

2
Theo kinh nghiệm của tôi, phương pháp này luôn gọi trình thu gom rác. Nó làm như vậy với đủ đều đặn rằng các lô sử dụng bộ nhớ của tôi so với số lượng đối tượng được khai báo luôn luôn là tuyến tính nghiêm ngặt (chiếm phần đệm, v.v.).
Jim Pivarski

Tôi đã nghĩ rằng bằng cách phân bổ các đối tượng mới và sau đó không tham khảo chúng nữa, trình thu gom rác sẽ tự động chạy
Bionix1441

@ PetrHudeček Trong các ứng dụng trong thế giới thực .NET GC.Collect()không thu thập. Trong Java gc()nào.
ajeh

53

Các thư viện jlibs có một lớp tiện ích tốt cho thu gom rác thải . Bạn có thể buộc thu gom rác bằng cách sử dụng một mẹo nhỏ tiện lợi với các đối tượng WeakReference .

RuntimeUtil.gc () từ jlibs:

   /**
    * This method guarantees that garbage collection is
    * done unlike <code>{@link System#gc()}</code>
    */
   public static void gc() {
     Object obj = new Object();
     WeakReference ref = new WeakReference<Object>(obj);
     obj = null;
     while(ref.get() != null) {
       System.gc();
     }
   }

1
Mã này bị hỏng vì một ref yếu bị xóa ngay khi tham chiếu của nó trở nên yếu có thể truy cập được, đó là trước khi nó bị xóa khỏi bộ nhớ.
Marko Topolnik

1
Bạn có thể kết hợp ý nghĩa của "GC đã chạy" với "bộ nhớ đã được lấy lại". Đối tượng vẫn sống và thậm chí chưa được hoàn thiện, nhưng bạn không thể truy cập nó nữa thông qua tham chiếu yếu. Một cách tốt hơn sẽ là sử dụng a PhantomReferencevới a ReferenceQueuevà sau đó bạn sẽ được thông báo sau khi hoàn thành, nhưng vẫn trước khi dọn dẹp. Cuối cùng, ngay cả khi bạn phát hiện thành công rằng bộ nhớ cho đối tượng này đã được lấy lại, nó vẫn có nghĩa là rất ít trong một thế hệ GC như HotSpot. Thông thường nó sẽ trùng với việc dọn dẹp thế hệ trẻ.
Marko Topolnik

20
OP đã yêu cầu và bạn tuyên bố sẽ cung cấp giải pháp "buộc thu gom rác". Chạy hệ thống con GC là một việc, thực sự thu gom rác khác. Mẫu mã bạn cung cấp rõ ràng có ý định đảm bảo rác đã được thu thập. Dù sao, đây là một câu hỏi rất cũ, rõ ràng không phải là về mong muốn của OP, mà là tiện ích cho công chúng. Không ai quan tâm đến việc "buộc hệ thống con GC tự chạy", không có rác được thu thập. Trong thực tế, mọi người thường muốn một sự đảm bảo rằng tất cả rác đã được thu thập.
Marko Topolnik

4
Bạn có thể đã không so sánh nó với hiệu quả của System.gc(); System.gc();nó, nhưng chắc chắn sẽ rất thú vị nếu biết nó có hoạt động tốt hơn thế không. Trong thực tế, chỉ cần in bao nhiêu lần nó System.gc()sẽ gọi là đủ. Cơ hội để đạt được 2 là khá mỏng.
Marko Topolnik

3
@MarkoTopolnik: 'Không ai quan tâm đến việc "buộc hệ thống con GC phải tự chạy", không có rác được thu thập' .... Thật ra tôi rất quan tâm đến hành vi này ngày hôm nay. Tôi rất biết ơn câu trả lời này đã có mặt. Mục đích của tôi là kiểm tra hành vi quay của xử lý nhật ký GC và nhận định dạng của đầu ra GC. Thủ thuật nhỏ này đã giúp tôi điền vào nhật ký GC một cách nhanh chóng.
erik.weathers

49

Cách tốt nhất (nếu không chỉ) để buộc một GC sẽ là viết một JVM tùy chỉnh. Tôi tin rằng các công cụ thu gom rác có thể cắm được nên bạn có thể chỉ cần chọn một trong những triển khai có sẵn và điều chỉnh nó.

Lưu ý: Đây KHÔNG phải là một câu trả lời dễ dàng.


40
+1 cho lulz. không có gì làm cho việc gỡ lỗi bực bội tốt hơn một người có khiếu hài hước. khác với một câu trả lời thực sự có thể sử dụng, đó là.
jsh


25

, gần như có thể buộc bạn phải gọi các phương thức theo cùng một thứ tự và đồng thời các phương thức này là:

System.gc ();
System.runFinalization ();

ngay cả khi chỉ là một đối tượng để làm sạch việc sử dụng hai phương thức này cùng một lúc, buộc bộ thu gom rác phải sử dụng finalise()phương thức của đối tượng không thể truy cập để giải phóng bộ nhớ được gán và thực hiện những gì finalize()phương thức nêu.

TUY NHIÊN Đó là một cách thực hành khủng khiếp khi sử dụng trình thu gom rác vì việc sử dụng phần mềm này có thể gây ra quá tải cho phần mềm thậm chí còn tệ hơn cả bộ nhớ, trình thu gom rác có luồng riêng không thể kiểm soát cộng tùy thuộc vào thuật toán được sử dụng bởi gc có thể mất nhiều thời gian hơn và được coi là rất kém hiệu quả, bạn nên kiểm tra phần mềm của mình nếu nó tệ nhất với sự trợ giúp của gc vì nó chắc chắn bị hỏng, một giải pháp tốt không phải phụ thuộc vào gc.

LƯU Ý: chỉ cần lưu ý rằng điều này sẽ chỉ hoạt động nếu trong phương thức hoàn thiện không phải là sự phân định lại đối tượng, nếu điều này xảy ra, đối tượng sẽ tiếp tục sống, nó sẽ hồi sinh về mặt kỹ thuật.


10
KHÔNG , thậm chí hai lệnh này sẽ KHÔNG ép buộc bộ sưu tập rác. Như đã được đề cập bởi những người khác, gc()chỉ là một gợi ý để chạy một bộ sưu tập rác. runFinalizers()chỉ chạy các công cụ hoàn thiện trên các đối tượng "đã bị phát hiện bị loại bỏ". Nếu gc không thực sự chạy, có thể không có vật thể nào như vậy ...
Steffen Heil

Ngoài ra, System.runFinalization () không đảm bảo rằng mọi thứ sẽ chạy; có thể không có gì sẽ xảy ra cả Đó là một gợi ý - từ Javadoc: " Gọi phương thức này cho thấy Máy ảo Java dành nỗ lực để chạy các phương thức hoàn thiện của các đối tượng đã được tìm thấy bị loại bỏ nhưng phương thức hoàn thiện chưa được chạy "
kaan

21

Theo tài liệu về OutOfMemoryError, nó tuyên bố rằng nó sẽ không bị ném trừ khi VM không lấy lại được bộ nhớ sau khi thu gom rác đầy đủ. Vì vậy, nếu bạn tiếp tục phân bổ bộ nhớ cho đến khi bạn gặp lỗi, bạn sẽ buộc phải có một bộ sưu tập rác đầy đủ.

Có lẽ câu hỏi mà bạn thực sự muốn hỏi là "làm thế nào tôi có thể lấy lại ký ức mà tôi nghĩ rằng tôi nên lấy lại bằng cách thu gom rác?"


18

Để yêu cầu thủ công GC (không phải từ System.gc ()):

  1. Chuyển đến thư mục bin trong JDK, vd.-C: \ Program Files \ Java \ jdk1.6.0_31 \ bin
  2. Mở jconsole.exe
  3. Kết nối với quy trình địa phương mong muốn.
  4. Chuyển đến tab bộ nhớ và nhấp vào thực hiện GC.

3
Phản đối gây hiểu lầm. Vui lòng di chuột vào nút "Thực hiện GC". Bạn có thể yêu cầu JVM thực hiện GC nhưng không bao giờ ép buộc.
Kumara

@PinkeshSharma, Điều này không bắt buộc . Đó là một yêu cầu đơn thuần có thể bị bỏ qua hoàn toàn.
Pacerier

@Pacerier Trong một thế giới lý tưởng có .. nhưng nếu bạn làm điều này, bạn sẽ thấy rằng có sự gia tăng bộ nhớ ngay lập tức ...
Pinkesh Sharma

11

.gc là một ứng cử viên để loại bỏ trong các bản phát hành trong tương lai - một Kỹ sư Mặt trời đã từng nhận xét rằng có thể ít hơn hai mươi người trên thế giới thực sự biết cách sử dụng .gc () - Tôi đã thực hiện một số công việc tối qua trong vài giờ cho một trung tâm / quan trọng cấu trúc dữ liệu bằng cách sử dụng dữ liệu được tạo bởi SecureRandom, tại một nơi nào đó vừa qua 40.000 đối tượng, vm sẽ chậm lại như thể nó đã hết con trỏ. Rõ ràng nó đã bị nghẹt thở trên các bảng con trỏ 16 bit và thể hiện hành vi "máy móc không hoạt động" cổ điển.

Tôi đã thử -Xms và cứ thế, cứ lặp đi lặp lại một chút cho đến khi nó chạy đến khoảng 57, xxx một cái gì đó. Sau đó, nó sẽ chạy gc đi từ 57.127 đến 57.128 sau một gc () - với tốc độ phình to mã ở trại Easy Money.

Thiết kế của bạn cần làm lại cơ bản, có thể là một cách tiếp cận cửa sổ trượt.


1
Tôi có một cái gì đó như thế, rất nhiều đối tượng trong bộ nhớ tôi không thể giải quyết chúng. Ngoại lệ OutOfMemory bị ném, tôi muốn Buộc GC kiểm tra xem có quá trình tạo Đối tượng vô hạn nào không hoặc các đối tượng này là hệ thống được sử dụng bởi hệ thống của tôi.

Có vẻ như bạn đang làm việc với cùng một vấn đề, tôi giải thích: "Tạo đối tượng vô hạn" ... dự án nghiên cứu tốt, có thể bạn có thể đăng câu hỏi hoặc nội dung nào đó trong khu vực java ở đây (Tôi sắp xếp mới ở đây và không biết "Automa hữu hạn" về cách thức hoạt động của trang web) Tôi đã thử ngày hôm qua và cuối cùng đã làm file.dat vì trình biên dịch phàn nàn "quá nhiều mã" trên 40.000 base36 BigIntegers được mã hóa thành một chuỗi cuối cùng tĩnh [] Tôi sẽ dính vào cổ tôi ở đây và suy đoán rằng toàn bộ JVM bị giới hạn trên các con trỏ 16 bit, tôi cá rằng những gì chúng ta phải làm là vô hiệu hóa và đọc từ đĩa ...
Nicholas Jordan

Thực sự, tôi không hiểu bạn. Nhưng để rõ ràng về "Tạo đối tượng vô hạn" Tôi có nghĩa là có một số đoạn mã trong hệ thống lớn của tôi tạo ra các đối tượng xử lý và tồn tại trong bộ nhớ, tôi thực sự không thể có được đoạn mã này, chỉ là cử chỉ !!

5
Vô lý! Có một trường hợp rõ ràng nên sử dụng: mã kiểm tra sử dụng các tham chiếu yếu, để chúng tôi có thể đảm bảo rằng hành vi đó là chính xác khi các tham chiếu yếu bị xóa.
Elias Vasylenko


6

Đặc tả JVM không nói bất cứ điều gì cụ thể về bộ sưu tập rác. Do đó, các nhà cung cấp có thể tự do thực hiện GC theo cách của họ.

Vì vậy, sự mơ hồ này gây ra sự không chắc chắn trong hành vi thu gom rác. Bạn nên kiểm tra chi tiết JVM của bạn để biết về các cách tiếp cận / thuật toán thu gom rác. Ngoài ra còn có các tùy chọn để tùy chỉnh hành vi là tốt.


4

Nếu bạn cần buộc thu gom rác, có lẽ bạn nên xem xét cách bạn quản lý tài nguyên. Bạn đang tạo ra các đối tượng lớn vẫn tồn tại trong bộ nhớ? Bạn có đang tạo các đối tượng lớn (ví dụ: các lớp đồ họa) có Disposablegiao diện và không gọi dispose()khi thực hiện với nó không? Bạn có đang khai báo một cái gì đó ở cấp độ lớp mà bạn chỉ cần trong một phương thức không?


2

Sẽ tốt hơn nếu bạn mô tả lý do tại sao bạn cần thu gom rác. Nếu bạn đang sử dụng SWT, bạn có thể loại bỏ các tài nguyên như ImageFontđể giải phóng bộ nhớ. Ví dụ:

Image img = new Image(Display.getDefault(), 16, 16);
img.dispose();

Ngoài ra còn có các công cụ để xác định tài nguyên không bị phát hiện.


Điều gì xảy ra nếu không có bất kỳ phương pháp xử lý nào?
ArifMustafa

1
Hoàn toàn không liên quan đến câu hỏi! Không, tôi không sử dụng SWT. Tôi đang gọi một phương thức JNI mở cửa sổ .NET thông qua lớp gốc Delphi. Tôi cũng có một lõi tính toán FORTRAN nhận dữ liệu thông qua lớp C ++ bản địa. Chuyện đó thì có liên quan gì? Tôi có thể ép buộc một GC hay không? Không? :-(
Mostafa Zeinali

0

Nếu bạn sắp hết bộ nhớ và nhận được một bộ nhớ, OutOfMemoryExceptionbạn có thể thử tăng lượng không gian heap có sẵn cho java bằng cách bắt đầu chương trình với java -Xms128m -Xmx512mthay vì chỉ java. Điều này sẽ cung cấp cho bạn kích thước heap ban đầu là 128Mb và tối đa 512Mb, cao hơn nhiều so với 32Mb / 128Mb tiêu chuẩn.


Cài đặt bộ nhớ mặc định làjava -Xms512M -Xmx1024M
ThePyroEagle

0

Một lựa chọn khác là không tạo đối tượng mới.

Đối tượng tổng hợp là để giảm nhu cầu GC trong Java.

Nhóm đối tượng nói chung sẽ không nhanh hơn việc tạo Đối tượng (đặc biệt đối với các đối tượng nhẹ) nhưng nhanh hơn so với Bộ sưu tập rác. Nếu bạn tạo 10.000 đối tượng và mỗi đối tượng là 16 byte. Đó là 160.000 byte GC phải lấy lại. Mặt khác, nếu bạn không cần tất cả 10.000 cùng một lúc, bạn có thể tạo một nhóm để tái chế / tái sử dụng các đối tượng loại bỏ nhu cầu xây dựng các đối tượng mới và loại bỏ nhu cầu đối với các đối tượng cũ.

Một cái gì đó như thế này (chưa được kiểm tra). Và nếu bạn muốn nó là chủ đề an toàn, bạn có thể trao đổi LinkedList cho một concienLinkedQueue.

public abstract class Pool<T> {
    private int mApproximateSize;
    private LinkedList<T> mPool = new LinkedList<>();

    public Pool(int approximateSize) {
        mApproximateSize = approximateSize;
    }

    public T attain() {
        T item = mPool.poll();
        if (item == null) {
            item = newInstance();
        }
        return item;
    }

    public void release(T item) {
        int approxSize = mPool.size(); // not guaranteed accurate
        if (approxSize < mApproximateSize) {
            recycle(item);
            mPool.add(item);
        } else if (approxSize > mApproximateSize) {
            decommission(mPool.poll());
        }
    }

    public abstract T newInstance();

    public abstract void recycle(T item);

    public void decommission(T item) { }

}

0

Trên OracleJDK 10 với G1 GC, một lệnh gọi System.gc()sẽ khiến cho GC dọn sạch Bộ sưu tập cũ. Tôi không chắc chắn nếu chạy ngay lập tức. Tuy nhiên, GC sẽ không dọn sạch Bộ sưu tập trẻ ngay cả khi System.gc()được gọi nhiều lần trong một vòng lặp. Để có được GC để dọn sạch Bộ sưu tập trẻ, bạn phải phân bổ trong một vòng lặp (ví dụ new byte[1024]) mà không cần gọi System.gc(). Gọi System.gc()cho một số lý do ngăn cản GC làm sạch Bộ sưu tập trẻ.


0

Thực sự, tôi không hiểu bạn. Nhưng để rõ ràng về "Tạo đối tượng vô hạn" Tôi có nghĩa là có một số đoạn mã trong hệ thống lớn của tôi tạo ra các đối tượng xử lý và tồn tại trong bộ nhớ, tôi thực sự không thể có được đoạn mã này, chỉ là cử chỉ !!

Điều này là chính xác, chỉ cử chỉ. Bạn có khá nhiều câu trả lời tiêu chuẩn đã được đưa ra bởi một số áp phích. Chúng ta hãy thực hiện từng cái một:

  1. Tôi không thể có được đoạn mã này

Chính xác, không có jvm thực tế - đó chỉ là một đặc điểm kỹ thuật, một nhóm khoa học máy tính mô tả một hành vi mong muốn ... Gần đây tôi đã đào sâu vào việc khởi tạo các đối tượng Java từ mã gốc. Để có được những gì bạn muốn, cách duy nhất là làm những gì được gọi là nulling tích cực. Những sai lầm nếu làm sai là làm xấu đến mức chúng ta phải giới hạn bản thân trong phạm vi ban đầu của câu hỏi:

  1. một số đoạn mã tại hệ thống lớn của tôi tạo ra các đối tượng

Hầu hết các áp phích ở đây sẽ cho rằng bạn đang nói rằng bạn đang làm việc với một giao diện, nếu vậy chúng tôi sẽ phải xem liệu bạn có đang trao toàn bộ vật thể hoặc một vật phẩm một lúc không.

Nếu bạn không còn cần một đối tượng, bạn có thể gán null cho đối tượng nhưng nếu bạn hiểu sai, có một ngoại lệ con trỏ null được tạo. Tôi cá là bạn có thể đạt được công việc tốt hơn nếu bạn sử dụng NIO

Bất cứ lúc nào bạn hoặc tôi hoặc bất kỳ ai khác nhận được: " Xin vui lòng tôi cần điều đó khủng khiếp. " Nó gần như là tiền thân của sự phá hủy gần như toàn bộ những gì bạn đang cố gắng làm .... viết cho chúng tôi một mã mẫu nhỏ, khử trùng mã thực tế được sử dụng và cho chúng tôi thấy câu hỏi của bạn.

Đừng nản lòng. Thông thường những gì điều này giải quyết là dba của bạn đang sử dụng một gói được mua ở đâu đó và thiết kế ban đầu không được điều chỉnh cho các cấu trúc dữ liệu lớn.

Điều đó rất phổ biến.


-1

FYI

Phương thức gọi System.runFinalulatorsOnExit (true) đảm bảo rằng các phương thức hoàn thiện được gọi trước khi Java tắt. Tuy nhiên, phương pháp này vốn không an toàn và đã bị phản đối. Một cách khác là thêm hook shutdown của máy móc với một phương thức Runtime.addShutdownHook.

Masarrat Siddiqui


Lỗ hổng với móc tắt máy là chúng hiếm khi thực sự hoạt động. Buộc chấm dứt không hoạt động, mã thoát không khác không hoạt động và đôi khi JVM (chính thức) đơn giản là không chạy chúng miễn là bạn cần chúng chạy.
ThePyroEagle

-1

Có một số cách gián tiếp để buộc người thu gom rác. Bạn chỉ cần điền vào đống với các đối tượng tạm thời cho đến thời điểm trình thu gom rác sẽ thực thi. Tôi đã tạo ra lớp học buộc người thu gom rác theo cách này:

class GarbageCollectorManager {

    private static boolean collectionWasForced;
    private static int refCounter = 0;

    public GarbageCollectorManager() {
        refCounter++;
    }

    @Override
    protected void finalize() {
        try {
            collectionWasForced = true;
            refCounter--;
            super.finalize();   
        } catch (Throwable ex) {
            Logger.getLogger(GarbageCollectorManager.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public int forceGarbageCollection() {
        final int TEMPORARY_ARRAY_SIZE_FOR_GC = 200_000;
        int iterationsUntilCollected = 0;
        collectionWasForced = false;

        if (refCounter < 2) 
            new GarbageCollectorManager();

        while (!collectionWasForced) {
            iterationsUntilCollected++;
            int[] arr = new int[TEMPORARY_ARRAY_SIZE_FOR_GC];
            arr = null;
        }

        return iterationsUntilCollected;
    }

}

Sử dụng:

GarbageCollectorManager manager = new GarbageCollectorManager();
int iterationsUntilGcExecuted = manager.forceGarbageCollection();

Tôi không biết phương pháp này hữu ích đến mức nào, bởi vì nó liên tục lấp đầy đống, nhưng nếu bạn có ứng dụng quan trọng, thì PHẢI buộc GC - khi đó có thể là cách di động Java để buộc GC.


"Final int TEMPORARY_ARRAY_SIZE_FOR_GC = 200_000;" là gì?
Koray Tugay

Kích thước mảng - có bao nhiêu đối tượng tạm thời (int's) sẽ được tạo để GC bắt đầu hoạt động.
Ag Pa Vasiliauskas 10/2/2015

Điều này có hợp lệ không: "_" trong một số nguyên?
Koray Tugay

1
Có, dấu gạch dưới bằng chữ số là hợp lệ bắt đầu từ Java SE 7. Điều này hữu ích, ví dụ như hàng ngàn dấu phân cách trong số nguyên như trong trường hợp này.
Ag Pa Vasiliauskas 10/2/2015

3
Bạn không bao giờ nên chạy mã như vậy trong một hệ thống sản xuất. Mặc dù mã này chạy trong một luồng, bất kỳ luồng nào khác cũng có thể nhận được OutOfMemoryException, hoàn toàn đảo ngược ý định gọi mã này ở vị trí đầu tiên ....
Steffen Heil

-1

Tôi muốn thêm một số điều ở đây. Xin lưu ý rằng Java chạy trên Máy ảo và không phải Máy thực tế. Máy ảo có cách giao tiếp riêng với máy. Nó có thể thay đổi từ hệ thống này sang hệ thống khác. Bây giờ Khi chúng tôi gọi cho GC, chúng tôi yêu cầu Máy ảo Java gọi Trình thu gom rác.

Vì Trình thu gom rác với Máy ảo, chúng tôi không thể buộc nó dọn dẹp ở đó và sau đó. Thay vào đó, chúng tôi xếp hàng yêu cầu của chúng tôi với Bộ sưu tập rác. Nó phụ thuộc vào Máy ảo, sau thời gian cụ thể (điều này có thể thay đổi từ hệ thống này sang hệ thống khác, thường là khi bộ nhớ ngưỡng được phân bổ cho JVM đầy) máy thực tế sẽ giải phóng không gian. : D


Câu đầu tiên của đoạn thứ hai là một sequitur không .
Hầu tước Lorne

-1

Đoạn mã sau được lấy từ phương thức assertGC (...). Nó cố gắng buộc người thu gom rác không phá hủy phải thu thập.

   List<byte[]> alloc = new ArrayList<byte[]>();
   int size = 100000;
   for (int i = 0; i < 50; i++) {
        if (ref.get() == null) {
             // Test succeeded! Week referenced object has been cleared by gc.
             return;
        }
        try {
             System.gc();
        } catch (OutOfMemoryError error) {
             // OK
        }
        try {
             System.runFinalization();
        } catch (OutOfMemoryError error) {
             // OK
        }

        // Approach the jvm maximal allocatable memory threshold
        try {
             // Allocates memory.
             alloc.add(new byte[size]);

             // The amount of allocated memory is increased for the next iteration.
             size = (int)(((double)size) * 1.3);
        } catch (OutOfMemoryError error) {
             // The amount of allocated memory is decreased for the next iteration.
             size = size / 2;
        }

        try {
             if (i % 3 == 0) Thread.sleep(321);
        } catch (InterruptedException t) {
             // ignore
        }
   }

   // Test failed! 

   // Free resources required for testing
   alloc = null;

   // Try to find out who holds the reference.
   String str = null;
   try {
        str = findRefsFromRoot(ref.get(), rootsHint);
   } catch (Exception e) {
        throw new AssertionFailedErrorException(e);
   } catch (OutOfMemoryError err) {
        // OK
   }
   fail(text + ":\n" + str);

Nguồn (Tôi đã thêm một số ý kiến ​​cho rõ ràng): Ví dụ NbTestCase


-1

Bạn có thể thử sử dụng Runtime.getRuntime().gc()hoặc sử dụng phương thức tiện ích System.gc()Lưu ý: Các phương pháp này không đảm bảo GC. Và phạm vi của chúng nên được giới hạn ở JVM thay vì xử lý theo chương trình trong ứng dụng của bạn.


2
Như đã giải thích trong các câu trả lời khác, các phương thức đó không bắt buộc chạy bộ sưu tập rác (hoàn chỉnh).
Dòng chảy

-2

Nếu bạn đang sử dụng JUnit và Spring, hãy thử thêm phần này vào mỗi lớp kiểm tra:

@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS)
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.