อวกาศอีเด็น
ดังนั้นคำถามของฉันอาจเป็นจริงได้และถ้าเป็นเช่นนั้นเหตุใดการจัดสรรฮีปของ Java จึงเร็วขึ้นมาก
ฉันกำลังศึกษาอยู่เล็กน้อยเกี่ยวกับการทำงานของ Java GC เนื่องจากมันน่าสนใจสำหรับฉัน ฉันพยายามขยายคอลเลกชันของกลยุทธ์การจัดสรรหน่วยความจำใน C และ C ++ เสมอ (สนใจที่จะลองใช้สิ่งที่คล้ายกันใน C) และมันเป็นวิธีที่เร็วและรวดเร็วมากในการจัดสรรออบเจ็กต์จำนวนมากในเวลาอันรวดเร็ว มุมมองการปฏิบัติ แต่ส่วนใหญ่เนื่องจากการมัลติเธรด
วิธีการทำงานของการจัดสรร Java GC คือการใช้กลยุทธ์การจัดสรรที่ประหยัดที่สุดเพื่อเริ่มต้นการจัดสรรออบเจ็กต์ให้กับพื้นที่ "Eden" จากสิ่งที่ฉันสามารถบอกได้ก็คือการใช้ตัวจัดสรรพูลตามลำดับ
นั่นคือทั้งหมดที่เร็วขึ้นมากเพียงแค่ในแง่ของอัลกอริทึมและลดข้อผิดพลาดของหน้าบังคับกว่าวัตถุประสงค์ทั่วไปmalloc
ใน C หรือเริ่มต้นโยนoperator new
ใน C ++
แต่ตัวจัดสรรแบบเรียงลำดับมีจุดอ่อนที่เห็นได้ชัด: พวกมันสามารถจัดสรรชิ้นขนาดแปรผันได้ แต่พวกมันไม่สามารถปล่อยชิ้นส่วนอิสระใด ๆ ได้ พวกเขาเพียงจัดสรรตามลำดับแบบตรงด้วยการแพ็ดดิ้งสำหรับการจัดตำแหน่งและสามารถล้างหน่วยความจำทั้งหมดที่จัดสรรในครั้งเดียวเท่านั้น โดยทั่วไปแล้วจะมีประโยชน์ใน C และ C ++ สำหรับการสร้างโครงสร้างข้อมูลซึ่งต้องการเพียงการแทรกและไม่มีการลบองค์ประกอบเช่นแผนผังการค้นหาที่จะต้องสร้างเพียงครั้งเดียวเมื่อโปรแกรมเริ่มทำงานจากนั้นจะค้นหาซ้ำ ๆ หรือเพิ่มคีย์ใหม่เท่านั้น ไม่มีการลบคีย์)
พวกเขายังสามารถใช้งานได้แม้สำหรับโครงสร้างข้อมูลที่อนุญาตให้องค์ประกอบถูกลบ แต่องค์ประกอบเหล่านั้นจะไม่ได้รับการปลดปล่อยจากหน่วยความจำจริง ๆ เพราะเราไม่สามารถยกเลิกการจัดสรรแต่ละรายการ โครงสร้างดังกล่าวที่ใช้ตัวจัดสรรแบบต่อเนื่องจะใช้หน่วยความจำมากขึ้นเรื่อย ๆเว้นแต่ว่าจะมีการส่งผ่านแบบเลื่อนเวลาบางส่วนซึ่งข้อมูลถูกคัดลอกไปยังสำเนาแบบใหม่ที่กระชับแล้วโดยใช้ตัวจัดสรรแบบเรียงลำดับแยกต่างหาก ไม่ได้ด้วยเหตุผลบางอย่าง - เพียงแค่จัดสรรสำเนาใหม่ของโครงสร้างข้อมูลให้ตรงตามลำดับและถ่ายโอนข้อมูลหน่วยความจำเก่าทั้งหมด)
ชุด
ในตัวอย่างโครงสร้างข้อมูล / สระว่ายน้ำเรียงลำดับข้างต้นมันจะเป็นปัญหาใหญ่ถ้า Java GC จัดสรรด้วยวิธีนี้แม้ว่ามันจะเร็วสุดสำหรับการจัดสรรระเบิดของแต่ละชิ้นจำนวนมาก มันจะไม่สามารถปล่อยให้เป็นอิสระได้จนกว่าซอฟต์แวร์จะปิดตัวลงซึ่ง ณ จุดนั้นก็จะสามารถล้าง (ล้าง) หน่วยความจำทั้งหมดในคราวเดียวได้
ดังนั้นหลังจากรอบ GC เดียวผ่านจะทำผ่านวัตถุที่มีอยู่ในพื้นที่ "Eden" (จัดสรรตามลำดับ) และคนที่ยังคงมีการอ้างอิงแล้วได้รับการจัดสรรโดยใช้ตัวจัดสรรวัตถุประสงค์ทั่วไปที่มีความสามารถในการปลดปล่อยชิ้นส่วนบุคคล คนที่ไม่มีการอ้างอิงอีกต่อไปจะได้รับการจัดสรรคืนในกระบวนการชำระล้าง ดังนั้นโดยทั่วไปมันคือ "คัดลอกวัตถุออกจากอวกาศอีเด็นถ้าพวกมันยังอ้างอิงอยู่
โดยทั่วไปจะมีราคาค่อนข้างแพงดังนั้นจึงทำในเธรดพื้นหลังแยกเพื่อหลีกเลี่ยงการเธรดที่ค้างไว้ซึ่งเดิมจัดสรรหน่วยความจำทั้งหมด
เมื่อหน่วยความจำถูกคัดลอกออกจากพื้นที่อีเด็นและจัดสรรโดยใช้โครงร่างที่มีราคาแพงกว่านี้ซึ่งสามารถปล่อยชิ้นส่วนอิสระหลังจากรอบ GC เริ่มต้นวัตถุจะย้ายไปยังพื้นที่หน่วยความจำถาวรมากขึ้น ชิ้นส่วนบุคคลเหล่านั้นจะได้รับการปลดปล่อยในรอบ GC ถัดไปหากพวกเขาหยุดที่จะอ้างอิง
ความเร็ว
ดังนั้นเหตุผลที่ Java GC อาจทำได้ดีกว่า C หรือ C ++ ที่การจัดสรรฮีปตรงเนื่องจากการใช้กลยุทธ์การจัดสรรที่ถูกที่สุดและเสื่อมโทรมที่สุดในเธรดที่ขอจัดสรรหน่วยความจำ จากนั้นมันจะบันทึกงานที่มีราคาแพงกว่าซึ่งปกติแล้วเราจะต้องทำเมื่อใช้ตัวจัดสรรทั่วไปเช่นเส้นตรงmalloc
สำหรับเธรดอื่น
ดังนั้นในความคิดจริงแล้ว GC ต้องทำงานโดยรวมให้มากขึ้น แต่มันกระจายไปทั่วเธรดเพื่อให้ต้นทุนเต็มไม่ได้จ่ายล่วงหน้าโดยเธรดเดี่ยว อนุญาตให้เธรดที่จัดสรรหน่วยความจำทำถูกสุด ๆ และจากนั้นเลื่อนการใช้จ่ายจริงที่จำเป็นในการทำสิ่งต่าง ๆ อย่างถูกต้องเพื่อให้แต่ละวัตถุสามารถถูกปล่อยให้เป็นเธรดอื่นได้อย่างแท้จริง ใน C หรือ C ++ เมื่อเราmalloc
หรือโทรoperator new
เราจะต้องจ่ายค่าใช้จ่ายเต็มจำนวนล่วงหน้าภายในเธรดเดียวกัน
นี่คือความแตกต่างที่สำคัญและทำไม Java ถึงมีประสิทธิภาพสูงกว่า C หรือ C ++ โดยใช้การเรียกที่ไร้เดียงสาmalloc
หรือoperator new
จัดสรรจำนวนชิ้นเล็ก ๆ ทีละรายการ แน่นอนว่าโดยทั่วไปจะมีการทำงานแบบปรมาณูและการล็อคที่เป็นไปได้เมื่อวงรอบ GC เริ่มเข้ามา
โดยทั่วไปคำอธิบายง่ายๆเดือดลงไปจ่ายเงินค่าใช้จ่ายหนักในหัวข้อเดียว ( malloc
) กับการจ่ายเงินค่าใช้จ่ายที่ถูกกว่าในหัวข้อเดียวแล้วการจ่ายเงินค่าใช้จ่ายหนักในอีกที่สามารถทำงานในแบบคู่ขนาน ( GC
) ในฐานะที่เป็นข้อเสียในการทำสิ่งต่าง ๆ ด้วยวิธีนี้หมายความว่าคุณต้องการสองทิศทางในการรับจากการอ้างอิงวัตถุไปยังวัตถุตามที่ต้องการเพื่อให้ผู้จัดสรรสามารถคัดลอก / ย้ายหน่วยความจำไปรอบ ๆ โดยไม่ทำให้การอ้างอิงวัตถุที่มีอยู่เป็นโมฆะ ย้ายออกจากพื้นที่ "Eden"
ท้ายสุด แต่ไม่ท้ายสุดการเปรียบเทียบนั้นค่อนข้างไม่ยุติธรรมเพราะรหัส C ++ ไม่ได้จัดสรรปริมาณของวัตถุเป็นจำนวนมากบนฮีป รหัส C ++ ที่ดีมีแนวโน้มที่จะจัดสรรหน่วยความจำสำหรับองค์ประกอบหลายอย่างในบล็อกที่ต่อเนื่องกันหรือบนสแต็ก หากจัดสรรจำนวนมากของวัตถุขนาดเล็กทีละตัวในร้านค้าฟรีรหัสนั้นจะเป็นสิ่งที่น่ารังเกียจ