จะบังคับให้รวบรวมขยะใน Java ได้อย่างไร


225

เป็นไปได้ไหมที่จะบังคับให้มีการรวบรวมขยะใน Java แม้ว่ามันจะยุ่งยากหรือไม่ ฉันรู้System.gc();และRuntime.gc();พวกเขาแนะนำให้ทำ GC เท่านั้น ฉันจะบังคับ GC ได้อย่างไร


30
บางทีอาจจะเป็นประโยชน์ในการให้ข้อมูลพื้นฐานสำหรับสาเหตุที่คุณต้องบังคับ GC โดยทั่วไปแล้วในภาษาที่รวบรวมขยะมันเป็นวิธีปฏิบัติที่ไม่ดีในการเรียกตัวสะสมอย่างชัดเจน
จัสติน Ethier

3
JVM ที่กำหนดอาจจัดเตรียมวิธีการรวบรวมขยะหลายวิธีแต่ละวิธีมีข้อดีและข้อเสียของตัวเองและบ่อยครั้งที่สามารถหลีกเลี่ยงสถานการณ์ที่กำหนดได้ง่ายๆ กรุณาอธิบายอย่างละเอียดเกี่ยวกับสถานการณ์
Thorbjørn Ravn Andersen

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

5
นี่คือกรณีการใช้งานเพื่อบังคับให้มีการรวบรวมขยะ: ฉันมีเซิร์ฟเวอร์ที่มีฮีป 30GB ซึ่งมักใช้ ~ 12GB (วัตถุ ~ 5M) ทุก ๆ 5 นาทีเซิร์ฟเวอร์ใช้เวลาประมาณหนึ่งนาทีในการดำเนินงานที่ซับซ้อนซึ่งใช้วัตถุเพิ่มเติม 35M โดยประมาณ GC แบบเต็มจะถูกเรียกใช้สองสามครั้งต่อชั่วโมงอย่างสม่ำเสมอในระหว่างงานที่ซับซ้อนและค้าง VM เป็นเวลา 10 ถึง 15 วินาที ฉันชอบที่จะบังคับให้ GC เต็มรูปแบบทำงานในเวลาที่งานที่ซับซ้อนไม่ได้ทำงานอยู่ มันจะเป็นการเล่นปาหี่ 5M วัตถุสดมากกว่า 40M
Steve

3
@JustinEthier มีกรณีที่เห็นได้ชัดอย่างหนึ่งที่คุณอาจต้องการบังคับใช้ GC ซึ่งเป็นหน่วยทดสอบพฤติกรรมที่เกี่ยวข้องกับ java.lang.ref.Reference ประเภทลำดับชั้น
Elias Vasylenko

คำตอบ:


168

ตัวเลือกที่ดีที่สุดของคุณคือการโทรหาSystem.gc()ซึ่งเป็นเพียงคำใบ้สำหรับตัวรวบรวมขยะที่คุณต้องการให้ทำเพื่อรวบรวม ไม่มีทางที่จะบังคับและเก็บอย่างฉับพลันแม้ว่าตัวเก็บรวบรวมขยะจะไม่สามารถกำหนดค่าได้


28
ควรมี non-deterministic == trouble
Pacerier

7
ตัวรวบรวมขยะอาจไม่สามารถกำหนดค่าได้และยังคงเสนอวิธีบังคับให้มีการรวบรวมทันที ตัวอย่างเช่นโดยทั่วไปตัวรวบรวม. NET จะไม่ได้กำหนดค่าไว้ แต่การเรียกไปยัง GC.Collect () บังคับให้เรียกใช้ เป็นเพียงว่า Java เลือกที่จะไม่เปิดเผยฟังก์ชันนี้
Petr Hudeček

2
จากประสบการณ์ของฉันวิธีนี้จะเรียกตัวเก็บรวบรวมขยะเสมอ มันมีความสม่ำเสมอเพียงพอที่แผนการหน่วยความจำของฉันใช้กับจำนวนวัตถุที่ประกาศนั้นจะเป็นแบบเชิงเส้นเสมอ (การบัญชีสำหรับการขยายและอื่น ๆ )
จิม Pivarski

ฉันคิดว่าการจัดสรรวัตถุใหม่แล้วไม่อ้างอิงพวกเขาอีกต่อไปตัวเก็บขยะจะทำงานโดยอัตโนมัติ
Bionix1441

@ PetrHudečekในโลกแห่งความจริงการสมัคร. NET GC.Collect()ไม่ได้เก็บรวบรวม ในชวาgc()ไม่
ajeh

53

ห้องสมุด jlibs มีระดับยูทิลิตี้ที่ดีสำหรับการเก็บขยะ คุณสามารถบังคับให้การรวบรวมขยะโดยใช้เคล็ดลับเล็ก ๆ น้อย ๆ กับวัตถุWeakReference

RuntimeUtil.gc ()จาก 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
รหัสนี้ใช้งานไม่ได้เนื่องจากการอ้างอิงแบบอ่อนได้รับการล้างทันทีที่ผู้อ้างอิงเข้าถึงได้ไม่สะดวกซึ่งก่อนที่จะถูกลบออกจากหน่วยความจำ
Marko Topolnik

1
คุณอาจกำลังสับสนเกี่ยวกับความหมายของ "GC ได้ทำงาน" กับ "หน่วยความจำได้รับการเรียกคืน" วัตถุยังมีชีวิตอยู่และยังไม่ได้สรุป แต่คุณไม่สามารถเข้าถึงได้อีกต่อไปผ่านการอ้างอิงที่อ่อนแอ เป็นวิธีที่ค่อนข้างดีกว่าจะใช้PhantomReferenceด้วยReferenceQueueและจากนั้นคุณจะได้รับแจ้งหลังจากการสรุป แต่ยังคงทำความสะอาดก่อน ในที่สุดแม้ว่าคุณจะตรวจพบสำเร็จว่าหน่วยความจำสำหรับวัตถุนี้ถูกเรียกคืนก็ยังคงมีความหมายน้อยมากใน GC generational เช่น HotSpot โดยปกติมันจะตรงกับการทำความสะอาดของคนรุ่นใหม่
Marko Topolnik

20
OP ขอและคุณอ้างว่าเป็นทางออกสำหรับ "บังคับให้มีการรวบรวมขยะ" การเรียกใช้ระบบย่อย GC เป็นสิ่งหนึ่งจริง ๆ แล้วรวบรวมขยะอีกอัน ตัวอย่างรหัสที่คุณให้ไว้ชัดเจนว่ามีเจตนารวบรวมขยะ อย่างไรก็ตามนี่เป็นคำถามที่เก่ามากมันไม่ได้เกี่ยวกับความปรารถนาของ OP แต่เป็นประโยชน์ต่อสาธารณชนทั่วไป ไม่มีใครสนใจที่จะ "บังคับให้ระบบย่อย GC รัน" ด้วยตัวเองโดยไม่มีการรวบรวมขยะ ในความเป็นจริงผู้คนมักต้องการการรับประกันว่ามีการรวบรวมขยะทั้งหมด
Marko Topolnik

4
คุณอาจไม่ได้เปรียบเทียบกับประสิทธิภาพของSystem.gc(); System.gc();มัน แต่มันน่าสนใจที่จะรู้ว่ามันใช้งานได้ดีกว่านั้นหรือไม่ ในความเป็นจริงเพียงพิมพ์จำนวนครั้งที่เรียกว่าSystem.gc()จะเพียงพอ โอกาสที่จะได้ถึง 2 นั้นค่อนข้างบาง
Marko Topolnik

3
@MarkoTopolnik: 'ไม่มีใครสนใจที่จะ "บังคับให้ระบบย่อย GC เรียกใช้" ด้วยตัวเองโดยไม่มีการเก็บขยะ' .... จริงๆแล้วฉันสนใจแค่พฤติกรรมนี้ในวันนี้ ฉันขอบคุณคำตอบนี้มีอยู่ จุดประสงค์ของฉันคือตรวจสอบพฤติกรรมการหมุนของการจัดการบันทึก GC และรับรูปแบบของเอาต์พุต GC เคล็ดลับเล็ก ๆ นี้ช่วยให้ฉันเติมบันทึก GC ได้อย่างรวดเร็ว
erik.weathers

49

วิธีที่ดีที่สุด (ถ้าไม่เพียง แต่) เพื่อบังคับให้ GC ต้องเขียน JVM ที่กำหนดเอง ฉันเชื่อว่านักสะสมขยะสามารถเสียบปลั๊กได้ดังนั้นคุณอาจจะเลือกใช้หนึ่งในนั้นและปรับแต่งมัน

หมายเหตุ: นี่ไม่ใช่คำตอบที่ง่าย


40
+1 สำหรับ lulz ไม่มีอะไรทำให้การดีบักที่น่าผิดหวังดีกว่าใครบางคนที่มีอารมณ์ขัน นอกเหนือจากคำตอบที่เป็นประโยชน์จริง ๆ นั่นคือ
jsh


25

ใช่เกือบจะเป็นไปได้ที่จะบังคับให้คุณต้องโทรหาวิธีการในลำดับเดียวกันและในเวลาเดียวกันสิ่งนี้คือ:

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

แม้ว่าจะเป็นเพียงวัตถุเดียวในการล้างการใช้สองวิธีนี้ในเวลาเดียวกันบังคับให้ตัวรวบรวมขยะใช้finalise()วิธีการของวัตถุที่ไม่สามารถเข้าถึงได้ซึ่งทำให้หน่วยความจำที่กำหนดไม่สามารถเข้าถึงได้และทำสิ่งที่finalize()วิธีนั้นระบุไว้

อย่างไรก็ตามมันเป็นวิธีปฏิบัติที่แย่มากที่จะใช้ตัวรวบรวมขยะเพราะการใช้มันสามารถแนะนำการโหลดเกินพิกัดให้กับซอฟต์แวร์ที่อาจเลวร้ายยิ่งกว่าในหน่วยความจำตัวเก็บขยะมีเธรดของตัวเองซึ่งไม่สามารถควบคุมได้และขึ้นอยู่กับ อัลกอริทึมที่ใช้โดย gc อาจใช้เวลามากขึ้นและพิจารณาว่าไม่มีประสิทธิภาพมากคุณควรตรวจสอบซอฟต์แวร์ของคุณถ้ามันแย่ที่สุดด้วยความช่วยเหลือของ gc เพราะมันพังแน่นอนทางออกที่ดีจะต้องไม่ขึ้นอยู่กับ gc

หมายเหตุ:โปรดจำไว้ว่าสิ่งนี้จะใช้ได้เฉพาะในวิธีการสุดท้ายไม่ใช่การกำหนดใหม่ของวัตถุหากสิ่งนี้เกิดขึ้นวัตถุจะยังมีชีวิตอยู่และจะมีการฟื้นคืนชีพซึ่งเป็นไปได้ทางเทคนิค


10
ไม่แม้แต่สองคำสั่งนี้จะไม่บังคับให้มีการรวบรวมขยะ ดังที่ผู้อื่นกล่าวถึงแล้วgc()เป็นเพียงคำแนะนำในการเรียกใช้การรวบรวมขยะ runFinalizers()รัน finalizers บนวัตถุเท่านั้น "ซึ่งถูกค้นพบว่าถูกทิ้ง" หากประชาคมโลกไม่ได้ทำงานจริงอาจจะไม่มีวัตถุดังกล่าว ...
เตฟเฟนไฮล์

นอกจากนี้System.runFinalization ()ไม่รับประกันว่าจะมีอะไรทำงาน เป็นไปได้ว่าจะไม่มีอะไรเกิดขึ้นเลย มันเป็นข้อเสนอแนะ - จาก Javadoc: "การเรียกใช้วิธีนี้แสดงให้เห็นว่า Java Virtual Machine ใช้ความพยายามในการดำเนินการขั้นตอนสุดท้ายของวัตถุที่พบว่าถูกทิ้ง แต่ยังไม่ได้เรียกใช้วิธีการสุดท้าย "
kaan

21

ภายใต้เอกสารประกอบสำหรับOutOfMemoryErrorมันจะประกาศว่าจะไม่ถูกส่งออกไปเว้นแต่ว่า VM จะไม่สามารถเรียกคืนหน่วยความจำหลังจากการรวบรวมขยะเต็ม ดังนั้นหากคุณจัดสรรหน่วยความจำต่อไปจนกว่าคุณจะได้รับข้อผิดพลาดคุณจะต้องบังคับให้มีการรวบรวมขยะเต็ม

คำถามที่คุณอยากถามจริงๆก็คือ "ฉันจะเรียกคืนหน่วยความจำที่ฉันคิดว่าฉันควรจะเรียกคืนได้ด้วยการรวบรวมขยะ"


18

หากต้องการร้องขอ GC (ไม่ใช่จาก System.gc ()) ด้วยตนเอง:

  1. ไปที่: โฟลเดอร์ bin ใน JDK เช่น -C: \ Program Files \ Java \ jdk1.6.0_31 \ bin
  2. เปิด jconsole.exe
  3. เชื่อมต่อกับกระบวนการท้องถิ่นที่ต้องการ
  4. ไปที่แท็บหน่วยความจำแล้วคลิกดำเนินการ GC

3
Oppsss ทำให้เข้าใจผิด กรุณาเลื่อนเมาส์ไปที่ปุ่ม "ดำเนินการ GC" คุณสามารถร้องขอให้ JVM ดำเนินการ GC แต่ไม่ต้องออกแรง
คูมารัน

@PinkeshSharma นี้ไม่ได้บังคับ มันเป็นเพียงแค่คำขอที่อาจถูกเพิกเฉยอย่างสิ้นเชิง
Pacerier

@Pacerier ในโลกอุดมคติใช่แล้ว .. แต่ถ้าคุณทำเช่นนี้คุณจะเห็นว่ามีหน่วยความจำเพิ่มขึ้นทันที ...
Pinkesh Sharma

11

.gc เป็นผู้สมัครเพื่อขจัดการปล่อยรุ่นต่อ ๆ ไป - วิศวกรของซันเคยแสดงความคิดเห็นว่าอาจมีคนในโลกน้อยกว่ายี่สิบคนที่รู้วิธีใช้. gc () - ฉันทำงานคืนหนึ่งเมื่อสองสามชั่วโมงที่ศูนย์ / สำคัญ โครงสร้างข้อมูลโดยใช้ข้อมูลที่สร้างโดย SecureRandom ที่บางที่ผ่านมา 40,000 วัตถุ vm จะช้าลงราวกับว่ามันหมดพอยน์เตอร์ เห็นได้ชัดว่ามันสำลักลงบนตารางตัวชี้ 16 บิตและแสดงพฤติกรรม "เครื่องจักรที่ล้มเหลว" แบบคลาสสิก

ฉันพยายาม -Xms และต่อ ๆ ไปเรื่อย ๆ นิด ๆ หน่อย ๆ จนกว่ามันจะวิ่งไปประมาณ 57, xxx อะไรบางอย่าง จากนั้นมันจะเรียกใช้ gc จาก 57,127 ไปเป็น 57,128 หลังจาก gc () - ที่ระดับความเร็วของโค้ดที่ค่าย Easy Money

การออกแบบของคุณต้องการการทำงานขั้นพื้นฐานอาจเป็นวิธีการเลื่อนหน้าต่าง


1
ฉันมีอะไรทำนองนั้นวัตถุมากมายในความทรงจำฉันไม่สามารถยกเลิกการจัดสรรได้ มีการโยนข้อยกเว้น OutOfMemory ฉันต้องการบังคับให้ GC ทดสอบว่ามีกระบวนการสร้างวัตถุไม่สิ้นสุดหรือวัตถุเหล่านี้เป็นระบบที่ใช้โดยระบบของฉันหรือไม่

ดูเหมือนว่าคุณกำลังทำงานกับปัญหาเดียวกันฉันอธิบาย: "การสร้างวัตถุที่ไม่มีที่สิ้นสุด" ... โครงการวิจัยที่ดีบางทีคุณสามารถโพสต์คำถามหรืออะไรในพื้นที่จาวาที่นี่ (ฉันเรียงลำดับใหม่ที่นี่และไม่ ทราบว่า "Finite Automa" ของเว็บไซต์ทำงานอย่างไร) ฉันลองเมื่อวานนี้และจบลงด้วยการทำ file.dat เมื่อคอมไพเลอร์บ่นว่า "รหัสมากเกินไป" ใน 40,000 base36 BigIntegers รหัส 36 เป็นสตริงสุดท้ายคงที่ [] ฉันจะติดคอของฉัน นี่และคาดการณ์ว่า JVM ทั้งหมดจะถูก จำกัด ในตัวชี้ 16 บิตฉันเดิมพันสิ่งที่เราต้องทำคือการ null อุกอาจและอ่านในจากดิสก์ ...
นิโคลัสจอร์แดน

จริง ๆ ฉันไม่ได้รับคุณ แต่เพื่อให้ชัดเจนเกี่ยวกับ "การสร้างวัตถุที่ไม่มีที่สิ้นสุด" ฉันหมายความว่ามีบางส่วนของรหัสที่ระบบขนาดใหญ่ของฉันทำการสร้างวัตถุที่จัดการและมีชีวิตอยู่ในความทรงจำฉันไม่สามารถรับรหัสชิ้นนี้จริง ๆ เพียงแค่ท่าทาง !!

5
เรื่องไร้สาระ! มีกรณีที่เห็นได้ชัดอย่างหนึ่งที่ควรใช้คือ: รหัสทดสอบที่ใช้การอ้างอิงแบบอ่อนเพื่อให้เราสามารถตรวจสอบพฤติกรรมที่ถูกต้องเมื่อการอ้างอิงแบบอ่อนได้ถูกลบทิ้ง
Elias Vasylenko

11

คุณสามารถทริกเกอร์ GC จากบรรทัดคำสั่ง สิ่งนี้มีประโยชน์สำหรับชุด / crontab:

jdk1.7.0/bin/jcmd <pid> GC.run

ดู:


1
ลองเพิ่มคำอธิบายความคิดเห็นหรือคำอธิบายเกี่ยวกับการอ้างอิง
veljasije

6

ข้อกำหนด JVM ไม่ได้พูดอะไรที่เฉพาะเจาะจงเกี่ยวกับการรวบรวมขยะ ด้วยเหตุนี้ผู้ขายจึงสามารถใช้งาน GC ได้อย่างอิสระ

ดังนั้นความไม่ชัดเจนนี้ทำให้เกิดความไม่แน่นอนในพฤติกรรมการเก็บขยะ คุณควรตรวจสอบรายละเอียด JVM ของคุณเพื่อทราบเกี่ยวกับแนวทาง / อัลกอริทึมการรวบรวมขยะ นอกจากนี้ยังมีตัวเลือกในการปรับแต่งพฤติกรรมเช่นกัน


4

หากคุณต้องการบังคับให้มีการรวบรวมขยะบางทีคุณควรพิจารณาว่าคุณจัดการทรัพยากรอย่างไร คุณกำลังสร้างวัตถุขนาดใหญ่ที่ยังคงอยู่ในหน่วยความจำหรือไม่? คุณกำลังสร้างวัตถุขนาดใหญ่ (เช่นคลาสกราฟิก) ที่มีDisposableอินเทอร์เฟซและไม่โทรdispose()เมื่อทำเสร็จหรือไม่ คุณกำลังประกาศบางสิ่งบางอย่างในระดับชั้นเรียนที่คุณต้องการเพียงวิธีเดียวหรือไม่?


2

มันจะดีกว่าถ้าคุณจะอธิบายเหตุผลที่คุณต้องการเก็บขยะ หากคุณใช้ SWT คุณสามารถกำจัดทรัพยากรเช่นImageและFontเพื่อเพิ่มหน่วยความจำ ตัวอย่างเช่น

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

นอกจากนี้ยังมีเครื่องมือในการกำหนดทรัพยากรที่ไม่ถูกเปิดเผย


เกิดอะไรขึ้นถ้าไม่มีวิธีการกำจัด?
ArifMustafa

1
ไม่เกี่ยวข้องกับคำถามโดยสิ้นเชิง! ไม่ฉันไม่ได้ใช้ SWT ฉันกำลังเรียกวิธีการ JNI ที่เปิดหน้าต่าง. NET ผ่านเลเยอร์ดั้งเดิมของ Delphi ฉันมีแกนการคำนวณ FORTRAN ที่รับข้อมูลผ่านเลเยอร์ C ++ ดั้งเดิม สิ่งนี้เกี่ยวข้องกับอะไร? ฉันสามารถบังคับ GC ได้หรือไม่? ไม่มี? :-(
Mostafa Zeinali

0

หากคุณกำลังวิ่งออกมาจากหน่วยความจำและได้รับOutOfMemoryExceptionคุณสามารถลองเพิ่มจำนวนของพื้นที่กองใช้ได้กับจาวาโดยเริ่มต้นที่คุณมีโปรแกรมแทนเพียงjava -Xms128m -Xmx512m javaสิ่งนี้จะทำให้คุณมีขนาดฮีพเริ่มต้นที่ 128Mb และสูงสุด 512Mb ซึ่งไกลเกินกว่ามาตรฐาน 32Mb / 128Mb


การตั้งค่าหน่วยความจำเริ่มต้นคือjava -Xms512M -Xmx1024M
ThePyroEagle

0

ตัวเลือกอื่นคือการไม่สร้างวัตถุใหม่

การรวมออบเจกต์ไม่อยู่เพื่อลดความต้องการ GC ใน Java

การรวมวัตถุโดยทั่วไปจะไม่เร็วกว่าการสร้างวัตถุ (โดยเฉพาะสำหรับวัตถุที่มีน้ำหนักเบา) แต่จะเร็วกว่าการรวบรวมขยะ หากคุณสร้าง 10,000 วัตถุและแต่ละวัตถุคือ 16 ไบต์ นั่นคือ 160,000 ไบต์ GC ต้องเรียกคืน ในทางกลับกันหากคุณไม่ต้องการ 10,000 ทั้งหมดในเวลาเดียวกันคุณสามารถสร้างพูลเพื่อรีไซเคิล / นำวัตถุที่ไม่จำเป็นต้องสร้างวัตถุใหม่มาใช้ใหม่และกำจัดความต้องการของวัตถุเก่า GC

บางสิ่งเช่นนี้ (ยังไม่ทดลอง) และถ้าคุณต้องการให้มันปลอดภัยต่อเธรดคุณสามารถสลับ LinkedList สำหรับ ConcurrentLinkedQueue

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

บน OracleJDK 10 ที่มี G1 GC การเรียกเพียงครั้งเดียวที่System.gc()จะทำให้ GC ทำความสะอาดคอลเล็กชันเก่า ฉันไม่แน่ใจว่า GC ทำงานได้ทันทีหรือไม่ อย่างไรก็ตาม GC จะไม่ล้างคอลเลกชัน Young แม้ว่าSystem.gc()จะมีการเรียกหลายครั้งในการวนซ้ำ ที่จะได้รับ GC ในการทำความสะอาดเก็บหนุ่มคุณต้องจัดสรรในวง (เช่นnew byte[1024]) System.gc()โดยไม่ต้องโทร โทรSystem.gc()เหตุผลบางอย่างที่จะช่วยป้องกันการ GC จากการทำความสะอาดเก็บหนุ่ม


0

จริง ๆ ฉันไม่ได้รับคุณ แต่เพื่อให้ชัดเจนเกี่ยวกับ "การสร้างวัตถุที่ไม่มีที่สิ้นสุด" ฉันหมายความว่ามีบางส่วนของรหัสที่ระบบขนาดใหญ่ของฉันทำการสร้างวัตถุที่จัดการและมีชีวิตอยู่ในความทรงจำฉันไม่สามารถรับรหัสชิ้นนี้จริง ๆ เพียงแค่ท่าทาง !!

ถูกต้องท่าทางเท่านั้น คุณมีคำตอบทั่วไปที่ผู้โพสต์หลายคนได้รับ เอาอันนี้ทีละอัน:

  1. ฉันไม่สามารถรับรหัสชิ้นนี้ได้จริง

ถูกต้องไม่มี jvm จริง - เป็นเพียงข้อมูลจำเพาะกลุ่มวิทยาการคอมพิวเตอร์ที่อธิบายพฤติกรรมที่ต้องการ ... ฉันเพิ่งขุดลงในการเริ่มต้นวัตถุ Java จากรหัสดั้งเดิม เพื่อให้ได้สิ่งที่คุณต้องการวิธีเดียวคือการทำสิ่งที่เรียกว่าก้าวร้าวโมฆะ ความผิดพลาดถ้าทำผิดนั้นแย่มากที่เราต้อง จำกัด ขอบเขตของคำถาม:

  1. โค้ดบางส่วนในระบบใหญ่ของฉันทำการสร้างวัตถุ

ผู้โพสต์ส่วนใหญ่ที่นี่จะถือว่าคุณกำลังพูดว่าคุณกำลังทำงานกับอินเทอร์เฟซถ้าเราจะต้องดูว่าคุณถูกส่งวัตถุทั้งหมดหรือรายการเดียวในเวลา

หากคุณไม่ต้องการวัตถุอีกต่อไปคุณสามารถกำหนด null ให้กับวัตถุได้ แต่หากคุณเข้าใจผิดจะมีข้อยกเว้นตัวชี้ null ที่สร้างขึ้น ฉันเดิมพันว่าคุณสามารถทำงานได้ดีขึ้นถ้าคุณใช้ NIO

เมื่อใดก็ตามที่คุณหรือฉันหรือใครก็ตามได้รับ: "ได้โปรดฉันต้องการสิ่งนั้นอย่างน่ากลัว " มันเป็นสิ่งที่เป็นสากลเกือบจะเป็นจุดเริ่มต้นของการทำลายล้างสิ่งที่คุณพยายามจะทำ รหัสจริงที่ใช้และแสดงคำถามของคุณให้เราทราบ

อย่าท้อแท้ บ่อยครั้งที่สิ่งนี้แก้ไขได้คือ DBA ของคุณใช้แพ็คเกจที่ซื้อที่ไหนสักแห่งและการออกแบบดั้งเดิมไม่ได้ถูกปรับแต่งสำหรับโครงสร้างข้อมูลขนาดใหญ่

นั่นเป็นเรื่องธรรมดามาก


-1

FYI

วิธีการเรียก System.runFinalizersOnExit (จริง) รับประกันว่าวิธีการ finalizer จะเรียกว่าก่อนที่จะปิดตัวลง Java อย่างไรก็ตามวิธีนี้ไม่ปลอดภัยโดยเนื้อแท้และได้รับการคัดค้าน อีกทางเลือกหนึ่งคือการเพิ่ม“ hooks ปิด” กับวิธีการ Runtime.addShutdownHook

Masarrat Siddiqui


ข้อบกพร่องที่เกี่ยวกับตะขอสำหรับปิดคือมันใช้งานไม่ค่อย การบังคับให้เลิกทำงานไม่ทำงานรหัสทางออกที่ไม่เป็นศูนย์จะไม่ทำงานและบางครั้ง JVM (เป็นทางการ) ก็ไม่ทำงานตราบใดที่คุณต้องการให้ทำงาน
ThePyroEagle

-1

มีวิธีอ้อมในการบังคับให้เก็บขยะ คุณเพียงแค่ต้องเติม heap ด้วยวัตถุชั่วคราวจนกว่าจะถึงเวลาที่ตัวรวบรวมขยะจะทำงาน ฉันได้สร้างคลาสที่บังคับให้นักสะสมขยะด้วยวิธีนี้:

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;
    }

}

การใช้งาน:

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

ฉันไม่ทราบว่าวิธีการนี้มีประโยชน์มากเพียงใดเพราะมันจะเติมฮีปอย่างต่อเนื่อง แต่ถ้าคุณมีแอปพลิเคชั่นที่สำคัญซึ่งต้องบังคับ GC - เมื่อนี่เป็นวิธีพกพา Java เพื่อบังคับ GC


"final int TEMPORARY_ARRAY_SIZE_FOR_GC = 200_000;" คืออะไร
Koray Tugay

ขนาดอาร์เรย์ - จำนวนวัตถุชั่วคราว (int's) ที่จะถูกสร้างขึ้นเพื่อให้ GC เริ่มทำงาน
Agnius Vasiliauskas

สิ่งนี้ถูกต้อง: "_" ในจำนวนเต็มหรือไม่
Koray Tugay

1
ใช่ขีดเส้นใต้ในตัวอักษรตัวเลขเริ่มต้นจาก Java SE 7 ซึ่งมีประโยชน์เช่นเป็นตัวคั่นหลักพันในจำนวนเต็มเช่นเดียวกับในกรณีนี้
Agnius Vasiliauskas

3
คุณไม่ควรเรียกใช้รหัสดังกล่าวในระบบที่ใช้งานจริง ในขณะที่รหัสนี้ทำงานในหนึ่งเธรดเธรดอื่น ๆ อาจได้รับ OutOfMemoryException อย่างสมบูรณ์พลิกกลับความตั้งใจที่จะเรียกสิ่งนี้ในสถานที่แรก ....
Steffen Heil

-1

ฉันต้องการเพิ่มบางสิ่งที่นี่ โปรดอย่าใช้ Java ที่ทำงานบนเครื่องเสมือนและไม่ใช่เครื่องจริง เครื่องเสมือนมีวิธีการสื่อสารกับเครื่องของตัวเอง มันอาจหลากหลายจากระบบไปยังระบบ ตอนนี้เมื่อเราเรียก GC เราขอให้ Virtual Machine of Java เรียก Garbage Collector

เนื่องจาก Garbage Collector อยู่กับ Virtual Machine เราจึงไม่สามารถบังคับให้ทำการล้างข้อมูลที่นั่นแล้ว ค่อนข้างว่าเราจะจัดคิวคำขอของเรากับ Garbage Collector ขึ้นอยู่กับเครื่องเสมือนหลังจากเวลาใดเวลาหนึ่ง (อาจเปลี่ยนจากระบบหนึ่งไปอีกระบบหนึ่งโดยทั่วไปเมื่อหน่วยความจำ threshold ที่จัดสรรให้กับ JVM เต็ม) เครื่องจริงจะเพิ่มพื้นที่ว่าง : D


ประโยคแรกของย่อหน้าที่สองเป็นแบบไม่ต่อเนื่อง
มาร์ควิสแห่ง Lorne

-1

รหัสต่อไปนี้นำมาจากเมธอด assertGC (... ) มันพยายามบังคับให้ตัวรวบรวมขยะ nondeterministic รวบรวม

   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);

แหล่งที่มา (ฉันเพิ่มความคิดเห็นเพื่อความชัดเจน): ตัวอย่าง NbTestCase


-1

คุณสามารถลองใช้Runtime.getRuntime().gc()หรือใช้วิธีอรรถประโยชน์System.gc()หมายเหตุ: วิธีการเหล่านี้ไม่แน่ใจว่า GC และขอบเขตของพวกเขาควร จำกัด อยู่ที่ JVM แทนที่จะจัดการด้วยโปรแกรมในแอปพลิเคชันของคุณ


2
ตามที่อธิบายไว้ในคำตอบอื่น ๆ วิธีการเหล่านั้นไม่ได้บังคับให้มีการเรียกใช้การรวบรวมขยะ (สมบูรณ์)
Flow

-2

หากคุณใช้ JUnit และ Spring ลองเพิ่มสิ่งนี้ในทุก ๆ คลาสการทดสอบ:

@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS)
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.