ทำไมการโทรถึง System.gc () จึงเป็นเรื่องไม่ถูกต้อง


326

หลังจากตอบคำถามเกี่ยวกับวิธีบังคับวัตถุฟรีใน Java (ชายคนนั้นกำลังล้าง HashMap 1.5GB) ด้วยSystem.gc()ฉันได้รับการบอกว่ามันเป็นวิธีปฏิบัติที่ไม่ถูกต้องในการโทรSystem.gc()ด้วยตนเอง แต่ความคิดเห็นนั้นไม่น่าเชื่อถืออย่างสิ้นเชิง นอกจากนี้ดูเหมือนว่าไม่มีใครกล้าที่จะลุกขึ้นสู้หรือถอนคำตอบของฉัน

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

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

ดังนั้นคำถามคือสองเท่าจริง:

  • เป็นเพราะเหตุใดหรือไม่ได้ปฏิบัติไม่ดีต่อการเรียกร้องSystem.gc()? จริง ๆ แล้วมันเป็นเพียงคำใบ้ของ JVM ภายใต้การนำไปใช้บางอย่างหรือเป็นวงจรการรวบรวมเต็มเสมอหรือไม่? มีการใช้งานตัวเก็บรวบรวมขยะที่สามารถทำงานได้โดยไม่หยุดโลกหรือไม่? กรุณาหลั่งน้ำตาแสงบางกว่ายืนยันต่าง ๆ คนได้ทำในการแสดงความคิดเห็นของฉันคำตอบ
  • เกณฑ์อยู่ที่ไหน มันเป็นสิ่งที่ไม่เคยมีความคิดที่ดีที่จะโทรSystem.gc()หรือจะมีบางครั้งที่มันเป็นที่ยอมรับ? ถ้าเป็นเช่นนั้นเวลาเหล่านั้นคืออะไร?

4
ฉันคิดว่าเวลาที่ดีในการโทรไปที่ System.gc () คือเมื่อคุณทำบางสิ่งที่เป็นกระบวนการโหลดที่ยาวอยู่แล้ว ตัวอย่างเช่นฉันกำลังทำงานกับเกมและวางแผนที่จะโทรหา System.gc () เมื่อเกมโหลดระดับใหม่เมื่อสิ้นสุดกระบวนการโหลด ผู้ใช้กำลังรออยู่แล้วและการเพิ่มประสิทธิภาพพิเศษอาจคุ้มค่า แต่ฉันจะวางตัวเลือกในหน้าจอการตั้งค่าเพื่อปิดการทำงานนี้
Ricket

41
Bozho: จดคำแรกของคำถาม ทำไมจึงเป็นวิธีที่ดีที่สุดที่จะไม่เรียกมัน? เพียงทำซ้ำมนต์ไม่ได้อธิบายสิ่งที่ถูกสาป
เพียงความคิดเห็นที่ถูกต้องของฉัน

1
อีกกรณีหนึ่งได้รับการอธิบายใน java-monitor.com/forum/showthread.php?t=188 ซึ่งจะอธิบายได้อย่างไรว่ามันเป็นการปฏิบัติที่ไม่ดีที่จะเรียก System.gc ()
Shirishkumar Bari

คำตอบ:


243

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

คุณไม่รู้ว่าคุณกำลังใช้ถังเก็บขยะประเภทใด มีบางอย่างที่ไม่"หยุดโลก"ตามที่คุณยืนยัน แต่ JVM บางคนไม่ฉลาดหรือด้วยเหตุผลต่าง ๆ (บางทีพวกเขาอยู่ในโทรศัพท์?) ไม่ทำ คุณไม่รู้ว่ามันกำลังจะทำอะไร

นอกจากนี้ยังไม่รับประกันว่าจะทำอะไร JVM อาจเพิกเฉยต่อคำขอของคุณทั้งหมด

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


แก้ไขเพื่อแก้ไขข้อกังวลเล็กน้อยจากเธรดอื่น:

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

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

หากต้องการแสดงว่าเป็นไปได้ที่System.gc()ไม่ทำอะไรเลยให้ดู:

http://bugs.sun.com/view_bug.do?bug_id=6668279

และโดยเฉพาะอย่างยิ่งว่ามีตัวเลือก-XX: DisableExplicitGC VM


1
คุณอาจสามารถสร้างการตั้งค่า Rube Goldberg-esque แปลก ๆ บางอย่างที่วิธีการทำงานของ GC มีผลต่อความถูกต้องของรหัสของคุณ บางทีมันอาจปิดบังการมีปฏิสัมพันธ์ของเธรดที่แปลกประหลาดหรือบางทีเครื่องมือปรับแต่งอาจมีผลกระทบอย่างมีนัยสำคัญต่อการทำงานของโปรแกรม ฉันไม่แน่ใจว่าเป็นไปได้ทั้งหมด แต่อาจเป็นไปได้ดังนั้นฉันจึงคิดว่าฉันจะพูดถึงมัน
Steven Schlansker

2
@zneak คุณอาจยกตัวอย่างได้ใส่รหัสที่สำคัญในการ finalizers (ซึ่งเสียพื้นฐาน code)
มาร์ติน

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

2
@AndrewJanke ฉันจะบอกว่ารหัสที่ใช้WeakReferences สำหรับวัตถุที่คุณต้องการที่จะถือไม่ถูกต้องตั้งแต่เริ่มต้นการเก็บขยะหรือไม่ คุณจะมีปัญหาเดียวกันใน C ++ ด้วยstd::weak_ptr(แม้ว่าคุณอาจสังเกตเห็นปัญหาในรุ่น C ++ ก่อนหน้านี้กว่าที่คุณจะเป็นในรุ่น Java เนื่องจากการทำลายวัตถุจะไม่ถูกเลื่อนออกไปเหมือนปกติจะเป็นขั้นสุดท้าย)
JAB

2
@rebeccah นั่นเป็นข้อผิดพลาดดังนั้นใช่ฉันจะเรียกมันว่า 'หักอย่างแน่นอน' ความจริงที่ว่าการSystem.gc()แก้ไขเป็นวิธีการแก้ปัญหาไม่ใช่วิธีการเข้ารหัสที่ดี
Steven Schlansker

149

มันได้รับการอธิบายแล้วว่าการโทรsystem.gc() อาจไม่ทำอะไรเลยและรหัสใด ๆ ที่ "ต้องการ" ตัวรวบรวมข้อมูลขยะที่จะเรียกใช้จะเสียหาย

อย่างไรก็ตามเหตุผลในทางปฏิบัติที่มันเป็นวิธีปฏิบัติที่ไม่ดีในการโทรSystem.gc()ก็คือมันไม่มีประสิทธิภาพ และในกรณีที่เลวร้ายที่สุดมันไม่มีประสิทธิภาพอย่างน่ากลัว ! ให้ฉันอธิบาย

อัลกอริทึม GC ทั่วไประบุขยะโดยการข้ามวัตถุที่ไม่ใช่ขยะทั้งหมดในกองและอนุมานว่าวัตถุใด ๆ ที่ไม่ได้เยี่ยมชมจะต้องเป็นขยะ จากนี้เราสามารถจำลองการทำงานทั้งหมดของการรวบรวมขยะประกอบด้วยส่วนหนึ่งซึ่งเป็นสัดส่วนกับปริมาณข้อมูลสดและอีกส่วนหนึ่งที่เป็นสัดส่วนกับปริมาณขยะ work = (live * W1 + garbage * W2)กล่าวคือ

ตอนนี้สมมติว่าคุณทำสิ่งต่อไปนี้ในแอปพลิเคชันแบบเธรดเดียว

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

การโทรครั้งแรกจะ (เราคาดการณ์) (live * W1 + garbage * W2)ทำงานและกำจัดขยะที่โดดเด่น

สายที่สองจะ(live* W1 + 0 * W2)ทำงานและเรียกคืนอะไร ในคำอื่น ๆ ที่เราได้ทำ(live * W1)การทำงานและประสบความสำเร็จไม่มีอะไรแน่นอน

เราสามารถสร้างแบบจำลองประสิทธิภาพของตัวสะสมเป็นปริมาณงานที่ต้องใช้ในการรวบรวมขยะ efficiency = (live * W1 + garbage * W2) / garbageกล่าวคือ ดังนั้นเพื่อให้ GC มีประสิทธิภาพมากที่สุดเราต้องเพิ่มค่าสูงสุดgarbageเมื่อเรารัน GC คือรอจนกว่ากองจะเต็ม (และทำฮีปให้ใหญ่ที่สุดเท่าที่จะเป็นไปได้ แต่นั่นเป็นหัวข้อแยกต่างหาก)

ถ้าสมัครไม่รบกวน (โดยการเรียกSystem.gc()) GC จะรอจนกว่ากองเต็มก่อนที่จะใช้ผลในคอลเลกชันที่มีประสิทธิภาพของขยะ1 แต่ถ้าแอปพลิเคชันบังคับให้ GC ทำงานอาจเป็นไปได้ว่าฮีปจะไม่เต็มและผลลัพธ์ที่ได้ก็คือการรวบรวมขยะอย่างไม่มีประสิทธิภาพ และบ่อยครั้งที่แอปพลิเคชันบังคับให้ GC ยิ่ง GC มีประสิทธิภาพมากขึ้น

หมายเหตุ: คำอธิบายข้างต้นคัดค้านความจริงที่ว่า GC ทั่วไปแบ่งพาร์ติชันฮีปเป็น "ช่องว่าง" GC อาจขยายฮีปแบบไดนามิกชุดการทำงานของแอปพลิเคชันของวัตถุที่ไม่ใช่ขยะอาจแตกต่างกันไป ดังนั้นแม้หลักพื้นฐานเช่นเดียวกับทั่วกระดานทุกสะสมขยะจริง2 มันไม่มีประสิทธิภาพในการบังคับให้ GC รัน


1 - นี่คือการทำงานของตัวสะสม "ปริมาณงาน" ตัวสะสมพร้อมกันเช่น CMS และ G1 ใช้เกณฑ์ที่แตกต่างกันในการตัดสินใจว่าเมื่อใดควรเริ่มต้นตัวรวบรวมขยะ

2 - ฉันยังไม่รวมตัวจัดการหน่วยความจำที่ใช้การนับการอ้างอิงโดยเฉพาะ แต่ไม่มีการใช้งานจาวาในปัจจุบันใช้วิธีการนั้น ... ด้วยเหตุผลที่ดี


45
+1 คำอธิบายที่ดี โปรดทราบว่าการใช้เหตุผลนี้ใช้ได้เฉพาะเมื่อคุณสนใจปริมาณงานเท่านั้น หากคุณต้องการเพิ่มประสิทธิภาพแฝงที่จุดเฉพาะการบังคับให้ GC อาจทำให้รู้สึก เช่น (พูดสมมุติ) ในเกมที่คุณอาจต้องการหลีกเลี่ยงความล่าช้าในระหว่างระดับ แต่คุณไม่สนใจเกี่ยวกับความล่าช้าในระหว่างการโหลดระดับ จากนั้นจะเป็นการสมเหตุสมผลที่จะบังคับให้ GC หลังจากโหลดระดับ มันลดปริมาณงานโดยรวม แต่นั่นไม่ใช่สิ่งที่คุณเพิ่มประสิทธิภาพ
sleske

2
@sleske - สิ่งที่คุณพูดนั้นเป็นความจริง อย่างไรก็ตามการรัน GC ระหว่างระดับต่าง ๆ นั้นเป็นวิธีแก้ปัญหาแบบใช้คลื่นความถี่ ... และไม่ได้แก้ปัญหาความล่าช้าหากระดับใช้เวลานานพอที่คุณจะต้องเรียกใช้ GC ในระหว่างระดับต่อไป วิธีที่ดีกว่าคือการใช้ตัวรวบรวมขยะที่เกิดขึ้นพร้อมกัน (หยุดชั่วคราว) ... หากแพลตฟอร์มรองรับ
Stephen C

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

@Kirk - "การโทรแบบสุ่มไปยัง System.gc () มักส่งผลให้มีค่าโสหุ้ยสูง GC" . ฉันรู้แล้ว. ดังนั้นใครก็ตามที่ได้อ่านและเข้าใจคำตอบของฉัน
Stephen C

@ Kirk - "ไม่แน่ใจว่าคุณหมายถึงอะไร ... " - ฉันหมายถึงโปรแกรมที่พฤติกรรม "ถูกต้อง" ของโปรแกรมขึ้นอยู่กับการทำงานของ GC ในเวลาที่กำหนด เช่นเพื่อดำเนินการขั้นสุดท้ายหรือทำลาย WeakReferences หรือ SoftReferences เป็นความคิดที่ดีจริงๆที่จะทำสิ่งนี้ ... แต่นี่คือสิ่งที่ฉันกำลังพูดถึง ดูคำตอบของ Steven Schlansker
Stephen C

47

ดูเหมือนว่ามีคนมากมายที่บอกคุณว่าอย่าทำเช่นนี้ ฉันไม่เห็นด้วย. หากหลังจากกระบวนการโหลดขนาดใหญ่เช่นการโหลดระดับคุณเชื่อว่า:

  1. คุณมีวัตถุจำนวนมากที่ไม่สามารถเข้าถึงได้และอาจไม่ได้ถูก gc'ed และ
  2. คุณคิดว่าผู้ใช้สามารถทนกับการชะลอตัวเล็กน้อยในจุดนี้

ไม่มีอันตรายในการโทร System.gc () ฉันดูคล้ายกับinlineคำหลักc / c ++ มันเป็นเพียงคำแนะนำสำหรับ gc ที่คุณนักพัฒนาได้ตัดสินใจว่าเวลา / ประสิทธิภาพไม่สำคัญเท่าที่ควรและบางส่วนสามารถใช้เรียกคืนหน่วยความจำได้

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

มีครั้งหนึ่งเมื่อฉันจะเป็นบังคับเมื่อพยายามที่จะหาเป็นโดยเฉพาะอย่างยิ่งการรั่วไหลของวัตถุ (ทั้งรหัสพื้นเมืองหรือใหญ่ปฏิสัมพันธ์โทรกลับซับซ้อนโอ้และองค์ประกอบ UI ใด ๆ ที่มากเป็นสายตาที่ Matlab..) คอลเลกชันนี้ไม่ควรนำมาใช้ ในรหัสการผลิต


3
+1 สำหรับ GC ในขณะที่วิเคราะห์การรั่วไหลของ mem โปรดทราบว่าข้อมูลเกี่ยวกับการใช้ฮีป (Runtime.freeMemory () และอื่น ๆ ) มีความหมายจริง ๆ หลังจากบังคับใช้ GC มิฉะนั้นจะขึ้นอยู่กับเมื่อระบบใส่ใจที่จะเรียกใช้ GC ครั้งล่าสุด
sleske

4
ไม่มีอันตรายใด ๆ ในการโทรไปที่ System.gc ()อาจต้องใช้stop the worldวิธีการและนี่คืออันตรายที่แท้จริงหากเกิดขึ้น
bestsss

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

Jetty ทำการโทร 2 ครั้งไปที่ System.gc () หลังจากเริ่มต้นและฉันไม่ค่อยเห็นว่าจะสร้างความแตกต่าง
Kirk

นักพัฒนาท่าเทียบเรือมีข้อผิดพลาด มันจะสร้างความแตกต่าง ... แม้ว่าความแตกต่างนั้นยากที่จะหาจำนวน
Stephen C

31

ผู้คนทำงานได้ดีอธิบายว่าทำไมไม่ใช้ดังนั้นฉันจะบอกคุณสองสามสถานการณ์ที่คุณควรใช้:

(ความคิดเห็นต่อไปนี้นำไปใช้กับ Hotspot ที่ทำงานบน Linux กับตัวรวบรวม CMS ซึ่งฉันรู้สึกมั่นใจว่าการที่System.gc()จริงแล้วจะเรียกใช้คอลเลกชันขยะเต็มรูปแบบเสมอ)

  1. หลังจากเริ่มต้นการทำงานของแอปพลิเคชันเริ่มต้นคุณอาจมีสถานะการใช้งานหน่วยความจำแย่มาก คนครึ่งรุ่นของคุณอาจเต็มไปด้วยขยะซึ่งหมายความว่าคุณอยู่ใกล้ CMS แรกของคุณมาก ในแอปพลิเคชันที่มีความสำคัญคุณไม่ควรเรียก System.gc () เพื่อ "รีเซ็ต" ฮีปของคุณให้อยู่ในสถานะเริ่มต้นของข้อมูลสด

  2. ในบรรทัดเดียวกันกับ # 1 หากคุณตรวจสอบการใช้ฮีปของคุณอย่างใกล้ชิดคุณต้องการให้มีการอ่านที่แม่นยำว่าการใช้งานหน่วยความจำพื้นฐานของคุณคืออะไร หากช่วงเวลา 2 นาทีแรกของการใช้งานแอพพลิเคชั่นของคุณเป็นการเริ่มต้นทั้งหมดข้อมูลของคุณจะถูกทำให้ยุ่งเหยิงเว้นแต่คุณจะบังคับ (อะแฮ่ม ... "แนะนำ") gc เต็มหน้า

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

  4. บางครั้งมีประโยชน์ที่จะต้องมีการเรียกใช้ System.gc ในแอปพลิเคชันที่ใช้งานจริงเพื่อตรวจสอบการมีอยู่ของหน่วยความจำรั่ว หากคุณรู้ว่าชุดข้อมูลสด ณ เวลา X ควรมีอยู่ในอัตราส่วนที่แน่นอนกับชุดข้อมูลสด ณ เวลา Y ดังนั้นการเรียกใช้ System.gc () ครั้ง X และเวลา Y และเปรียบเทียบการใช้หน่วยความจำ .


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

11

นี่เป็นคำถามที่น่ารำคาญอย่างมากและฉันรู้สึกว่ามีส่วนช่วยในการต่อต้าน Java มากแม้ว่าจะมีประโยชน์ในการใช้ภาษา

ความจริงที่ว่าคุณไม่สามารถไว้วางใจ "System.gc" ในการทำอะไรได้อย่างไม่น่าเชื่อและสามารถเรียกใช้ "ความกลัว, ความไม่แน่นอน, ข้อสงสัย" ได้อย่างง่ายดาย

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

การมีความสามารถในการควบคุมการรวบรวมขยะจะเป็นเครื่องมือการศึกษาที่ยอดเยี่ยมในการปรับปรุงความเข้าใจของผู้คนเกี่ยวกับวิธีการทำงานของการรวบรวมขยะและวิธีการทำให้โปรแกรมใช้ประโยชน์จากพฤติกรรมเริ่มต้นเช่นเดียวกับพฤติกรรมที่ควบคุม

ให้ฉันตรวจสอบข้อโต้แย้งของหัวข้อนี้

  1. มันไม่มีประสิทธิภาพ:

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

  1. เป็นแนวปฏิบัติที่ไม่ดีเสมอและระบุรหัสที่ใช้ไม่ได้

ฉันไม่เห็นด้วยไม่สำคัญว่าคุณมีคนเก็บขยะ หน้าที่ของมันคือการติดตามขยะและทำความสะอาด

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

แน่นอนว่ามันอาจไม่ทำงานตามที่คุณต้องการหรือคาดหวัง แต่เมื่อคุณต้องการโทรหาคุณจะรู้ว่าไม่มีอะไรเกิดขึ้นและผู้ใช้ยินดีที่จะทนต่อความเชื่องช้า / การหยุดทำงาน ถ้า System.gc ใช้งานได้ดีมาก! หากไม่เป็นเช่นนั้นอย่างน้อยคุณก็ลอง ไม่มีข้อเสียเลยเว้นแต่ตัวรวบรวมขยะจะมีผลข้างเคียงโดยธรรมชาติที่ทำสิ่งที่ไม่คาดคิดอย่างน่ากลัวว่าตัวเก็บขยะนั้นควรทำตัวอย่างไรหากเรียกใช้ด้วยตนเองและสิ่งนี้เองทำให้เกิดความไม่ไว้วางใจ

  1. มันไม่ใช่กรณีการใช้งานทั่วไป:

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

  1. ข้อมูลจำเพาะระบุว่า System.gc () เป็นคำใบ้ที่ GC ควรรันและ VM มีอิสระที่จะเพิกเฉยได้

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

เมื่อพูดถึง GC ของ Java มักจะดูเหมือนสัตว์ประหลาดที่คุณไม่ไว้ใจ คุณไม่รู้ว่ามันกำลังจะมาหรือไปคุณไม่รู้ว่ามันกำลังจะทำอะไรมันจะทำยังไง ฉันสามารถจินตนาการได้ว่าผู้เชี่ยวชาญบางคนมีความคิดที่ดีกว่าว่า Garbage Collection ของพวกเขาทำงานอย่างไรตามคำสั่ง แต่ส่วนใหญ่ก็หวังว่ามันจะ "ได้ผล" และต้องเชื่อใจอัลกอริธึมที่ดูเหมือนทึบแสงในการทำงานให้คุณ

มีช่องว่างขนาดใหญ่ระหว่างการอ่านเกี่ยวกับบางสิ่งบางอย่างหรือกำลังสอนอะไรบางอย่างและเห็นการใช้งานจริงความแตกต่างระหว่างระบบต่าง ๆ และสามารถเล่นกับมันได้โดยไม่ต้องดูซอร์สโค้ด สิ่งนี้สร้างความมั่นใจและความรู้สึกของผู้เชี่ยวชาญ / ความเข้าใจ / การควบคุม

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

มันอาจจะไม่เป็นไรที่ Java GC จะทำงานในแบบที่มันทำหรืออาจจะไม่ใช่ แต่ถ้าจะเข้าใจมันเป็นการยากที่จะทำตามอย่างแท้จริงในทิศทางที่จะไปรับภาพรวมที่ครอบคลุมของสิ่งที่คุณสามารถไว้วางใจ GC ให้ทำ ไม่ต้องทำดังนั้นมันง่ายเกินไปที่จะเชื่อใจภาษาเพราะจุดประสงค์ของภาษาคือการควบคุมพฤติกรรมในระดับปรัชญา (เป็นเรื่องง่ายสำหรับโปรแกรมเมอร์โดยเฉพาะอย่างยิ่งผู้ฝึกหัดโดยเฉพาะอย่างยิ่งผู้ฝึกหัดที่ตกอยู่ในภาวะวิกฤติจากพฤติกรรมของระบบ / ภาษา) มีความสามารถในการทน (และถ้าคุณไม่สามารถคุณจะไม่ใช้ภาษาจนกว่าคุณจะต้อง) และสิ่งอื่น ๆ ที่คุณไม่สามารถควบคุมได้โดยไม่รู้เหตุผลว่าทำไมคุณไม่สามารถควบคุมพวกเขาเป็นอันตรายโดยเนื้อแท้


9

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

การโทรSystem.gc()ก็เหมือนกับการเตะ GC มันหมายถึง: "ทุกพารามิเตอร์ที่ปรับจูนอย่างระมัดระวังองค์กรอัจฉริยะเหล่านั้นความพยายามทั้งหมดที่คุณใส่ลงไปในการจัดสรรและจัดการวัตถุเพื่อให้สิ่งต่าง ๆ ดำเนินไปอย่างราบรื่นดีเพียงแค่วางล็อตทั้งหมดและเริ่มจากศูนย์" มันอาจปรับปรุงประสิทธิภาพ แต่ส่วนใหญ่จะลดประสิทธิภาพลง

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

(*) ฉันกำลังพูดถึงประสิทธิภาพที่นี่ System.gc()จะไม่ทำลายโปรแกรม Java ที่ถูกต้อง มันจะไม่คิดในความทรงจำเพิ่มเติมที่ JVM ไม่สามารถได้รับเป็นอย่างอื่น: ก่อนที่จะโยนOutOfMemoryErrorJVM ทำงานของSystem.gc()แม้ว่าจะเป็นทางเลือกสุดท้าย


1
+1 สำหรับการกล่าวถึงว่า System.gc () ไม่ได้ป้องกัน OutOfMemoryError บางคนเชื่อเรื่องนี้
sleske

1
ที่จริงแล้วมันอาจป้องกัน OutOfMemoryError เนื่องจากการจัดการอ้างอิงนุ่ม SoftReferences ที่สร้างขึ้นหลังจากการรัน GC ครั้งสุดท้ายไม่ได้รับการรวบรวมในการนำไปใช้ที่ฉันรู้ แต่นี่คือรายละเอียดการใช้งานอาจมีการเปลี่ยนแปลงได้ตลอดเวลาและเป็นข้อผิดพลาดและคุณไม่ต้องพึ่งพา
maaartinus

8

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

หลายปีที่ผ่านมาฉันทำงานกับเครื่องกำเนิดรายงาน

  • มีหัวข้อเดียว
  • อ่าน "คำขอรายงาน" จากคิว
  • โหลดข้อมูลที่จำเป็นสำหรับรายงานจากฐานข้อมูล
  • สร้างรายงานและส่งอีเมลออก
  • ทำซ้ำตลอดไปนอนเมื่อไม่มีคำขอที่โดดเด่น
  • มันไม่ได้ใช้ซ้ำข้อมูลใด ๆ ระหว่างรายงานและไม่ได้ทำการแคชใด ๆ

ประการแรกเนื่องจากไม่ใช่เรียลไทม์และผู้ใช้คาดว่าจะรอรายงานความล่าช้าในขณะที่การรัน GC ไม่ใช่ปัญหา แต่เราต้องสร้างรายงานในอัตราที่เร็วกว่าที่พวกเขาร้องขอ

เมื่อมองไปที่ร่างของกระบวนการข้างต้นมันชัดเจนว่า

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

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

อาจเป็นการดีที่การรัน GC หลังจากส่งรายงานแต่ละฉบับทางอีเมลเนื่องจากเรารู้ว่านี่เป็นเวลาที่ดีสำหรับการรัน GC อย่างไรก็ตามหากคอมพิวเตอร์มี ram เพียงพอจะได้ผลลัพธ์ที่ดีกว่าโดยการชะลอการรัน GC

พฤติกรรมนี้ได้รับการกำหนดค่าตามฐานการติดตั้งสำหรับลูกค้าบางรายที่เปิดใช้งาน GC บังคับหลังจากแต่ละรายงานเร่งการปกป้องรายงานอย่างรวดเร็ว (ฉันคาดหวังว่านี่เป็นเพราะหน่วยความจำเหลือน้อยในเซิร์ฟเวอร์ของพวกเขาและมันทำงานกระบวนการอื่นจำนวนมากดังนั้นจึงเป็นช่วงเวลาที่ดีที่ GC บังคับให้ลดการเพจจิ้ง)

เราไม่เคยตรวจพบการติดตั้งที่ไม่ได้รับประโยชน์คือการบังคับให้ GC รันทุกครั้งที่คิวงานว่างเปล่า

แต่ขอให้ชัดเจนข้างต้นไม่ใช่กรณีทั่วไป


3

บางทีฉันอาจจะเขียนรหัสเส็งเคร็ง แต่ฉันก็ตระหนักว่าการคลิกที่ไอคอนถังขยะบน eclipse และ netbeans IDEs เป็นวิธีปฏิบัติที่ดี


1
อาจเป็นเช่นนั้น แต่ถ้า Eclipse หรือ NetBeans ถูกตั้งโปรแกรมให้โทรSystem.gc()เป็นระยะคุณอาจพบว่าพฤติกรรมน่ารำคาญ
Stephen C

2

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

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

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


3
"ความจริงคือ VM จะไม่เพิกเฉยต่อการเรียกไปยัง System.gc ()" - ไม่ถูกต้อง อ่านเกี่ยวกับ -XX: -DisableExplicitGC
Stephen C

1

ใช่การเรียก System.gc () ไม่รับประกันว่าจะทำงานได้ แต่เป็นคำขอไปยัง JVM ที่อาจถูกเพิกเฉย จากเอกสาร:

การเรียกใช้เมธอด gc แสดงให้เห็นว่า Java Virtual Machine ใช้ความพยายามในการรีไซเคิลวัตถุที่ไม่ได้ใช้

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

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


<จังหวะ> แต่จาก Javadoc: _ เมื่อการควบคุมกลับมาจากการเรียกใช้เมธอดเครื่องเสมือนพยายามอย่างเต็มที่เพื่อรีไซเคิลวัตถุที่ถูกทิ้งทั้งหมดซึ่งฉันเห็นว่าเป็นรูปแบบที่มีความจำเป็นมากขึ้นของสิ่งที่คุณโพสต์ > สกรูนั้นมีรายงานข้อผิดพลาดเกี่ยวกับการทำให้เข้าใจผิด จากการที่รู้ดีกว่าอะไรคืออันตรายของคำใบ้ JVM?
zneak

1
อันตรายคือการทำคอลเลกชันในเวลาที่ผิดอาจช้าลงอย่างมาก คำใบ้ที่คุณให้อาจเป็นสิ่งที่ไม่ดี สำหรับความคิดเห็นที่ "ดีที่สุด" ลองและดูในเครื่องมืออย่าง JConsole บางครั้งการคลิกปุ่ม "ทำการ GC" ไม่ได้ผลใด ๆ
tom

ขออภัยที่ไม่เห็นด้วย แต่โทรหา System.gc () ใน OpenJDK และทุกอย่างที่เป็นไปตามนั้น (เช่น HP) จะส่งผลให้เกิดรอบการรวบรวมขยะ ในความเป็นจริงที่ดูเหมือนว่าเป็นจริงของการดำเนิน J9 ของ IBM ด้วย
Kirk

@Kirk - ไม่ถูกต้อง: google และอ่านเกี่ยวกับ -XX: -DisableExplicitGC
สตีเฟ่นซี

0

จากประสบการณ์ของฉันการใช้ System.gc () เป็นรูปแบบการเพิ่มประสิทธิภาพเฉพาะแพลตฟอร์มอย่างมีประสิทธิภาพ (โดยที่ "แพลตฟอร์ม" คือการรวมกันของสถาปัตยกรรมฮาร์ดแวร์, OS, รุ่น JVM และพารามิเตอร์รันไทม์ที่เป็นไปได้เพิ่มเติมเช่น RAM ที่มี) ในขณะที่ประมาณคร่าวๆบนแพลตฟอร์มเฉพาะสามารถ (และจะ) แตกต่างกันมากระหว่างแพลตฟอร์ม

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

แต่ไม่ว่ามันจะช่วยหรือทำร้าย (หรือไม่ทำอะไรเลย) เป็นอย่างมากขึ้นอยู่กับแพลตฟอร์ม (ตามที่กำหนดไว้ด้านบน)

ดังนั้นฉันคิดว่ามันถูกต้องเป็นการเพิ่มประสิทธิภาพเฉพาะแพลตฟอร์มสุดท้าย (เช่นถ้าการเพิ่มประสิทธิภาพอื่น ๆ ไม่เพียงพอ) แต่คุณไม่ควรเรียกมันเพียงเพราะคุณเชื่อว่ามันอาจช่วยได้ (โดยไม่มีการวัดประสิทธิภาพที่เฉพาะเจาะจง) เพราะโอกาสที่มันจะไม่เป็นเช่นนั้น


0
  1. เนื่องจากวัตถุได้รับการจัดสรรแบบไดนามิกโดยใช้ตัวดำเนินการใหม่
    คุณอาจสงสัยว่าวัตถุดังกล่าวถูกทำลายและ
    หน่วยความจำที่ถูกปล่อยออกมาเพื่อการจัดสรรใหม่ในภายหลังได้อย่างไร

  2. ในบางภาษาเช่น C ++ วัตถุที่จัดสรรแบบไดนามิกต้องถูกปล่อยด้วยตนเองโดยใช้ตัวดำเนินการลบ

  3. Java ใช้แนวทางที่แตกต่าง มันจัดการการจัดสรรคืนสำหรับคุณโดยอัตโนมัติ
  4. เทคนิคที่ทำให้สิ่งนี้สำเร็จเรียกว่าการรวบรวมขยะ การทำงานเช่นนี้: เมื่อไม่มีการอ้างอิงไปยังวัตถุวัตถุนั้นจะไม่จำเป็นต้องใช้อีกต่อไปและหน่วยความจำที่ครอบครองโดยวัตถุนั้นสามารถเรียกคืนได้ ไม่จำเป็นต้องทำลายวัตถุอย่างชัดเจนใน C ++
  5. การรวบรวมขยะจะเกิดขึ้นเป็นระยะ ๆ เท่านั้น (หากเลย) ระหว่างการดำเนินการโปรแกรมของคุณ
  6. มันจะไม่เกิดขึ้นเพียงเพราะมีวัตถุหนึ่งชิ้นหรือมากกว่านั้นที่ไม่ได้ใช้อีกต่อไป
  7. นอกจากนี้การใช้งานรันไทม์ Java ที่แตกต่างกันจะใช้วิธีการที่แตกต่างกันในการเก็บขยะ แต่ส่วนใหญ่คุณไม่ควรคิดในขณะที่เขียนโปรแกรมของคุณ
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.