การใช้ขั้นสุดท้ายสำหรับตัวแปรใน Java ช่วยปรับปรุงการรวบรวมขยะหรือไม่


86

วันนี้เพื่อนร่วมงานของฉันและฉันมีการอภิปรายเกี่ยวกับการใช้finalคำหลักใน Java เพื่อปรับปรุงการรวบรวมขยะ

ตัวอย่างเช่นหากคุณเขียนวิธีการเช่น:

public Double doCalc(final Double value)
{
   final Double maxWeight = 1000.0;
   final Double totalWeight = maxWeight * value;
   return totalWeight;  
}

การประกาศตัวแปรในเมธอดfinalจะช่วยให้การรวบรวมขยะล้างหน่วยความจำจากตัวแปรที่ไม่ได้ใช้ในเมธอดหลังจากที่เมธอดออกไป

นี่คือเรื่องจริง?


ที่จริงมีอยู่สองอย่าง 1) เมื่อคุณเขียนลงในฟิลด์ local method และอินสแตนซ์ เมื่อคุณเขียนถึงอินสแตนซ์อาจมีประโยชน์
Eugene

คำตอบ:


86

นี่คือตัวอย่างที่แตกต่างกันเล็กน้อยตัวอย่างหนึ่งที่มีฟิลด์ประเภทการอ้างอิงขั้นสุดท้ายแทนที่จะเป็นตัวแปรโลคัลประเภทค่าสุดท้าย:

public class MyClass {

   public final MyOtherObject obj;

}

ทุกครั้งที่คุณสร้างอินสแตนซ์ของ MyClass คุณจะต้องสร้างการอ้างอิงขาออกไปยังอินสแตนซ์ MyOtherObject และ GC จะต้องไปตามลิงก์นั้นเพื่อค้นหาวัตถุที่มีชีวิต

JVM ใช้อัลกอริทึม GC แบบกวาดเครื่องหมายซึ่งต้องตรวจสอบการอ้างอิงสดทั้งหมดในตำแหน่ง "root" ของ GC (เช่นเดียวกับวัตถุทั้งหมดใน call stack ปัจจุบัน) วัตถุที่มีชีวิตแต่ละชิ้นจะถูก "ทำเครื่องหมาย" ว่ามีชีวิตและวัตถุใด ๆ ที่อ้างถึงโดยวัตถุที่มีชีวิตจะถูกทำเครื่องหมายว่ามีชีวิต

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

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

ผมจะบอกว่า "ไม่" โมดิเฟอร์ "ขั้นสุดท้าย" ไม่ได้ช่วยให้ GC ลดภาระงานลง "

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

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

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


อาหารสมอง. ฉันมักจะคิดว่าโค้ดอินไลน์นั้นเร็วกว่า แต่ถ้า jvm ใช้หน่วยความจำสั้นมันก็จะช้าเช่นกัน
อืมม

1
ฉันแค่เดาที่นี่ ... แต่ฉันคิดว่าคอมไพเลอร์ JIT สามารถอินไลน์ค่าดั้งเดิมขั้นสุดท้าย (ไม่ใช่วัตถุ) เพื่อเพิ่มประสิทธิภาพเล็กน้อย ในทางกลับกันการใส่โค้ดสามารถสร้างการเพิ่มประสิทธิภาพที่สำคัญได้ แต่ไม่เกี่ยวข้องกับตัวแปรสุดท้าย
benjismith

2
เป็นไปไม่ได้ที่จะกำหนดค่าว่างให้กับวัตถุสุดท้ายที่สร้างขึ้นแล้วบางทีสุดท้ายแทนที่จะเป็นความช่วยเหลืออาจทำให้สิ่งต่างๆยากขึ้น
Hernán Eche

1
เราสามารถใช้ {} เพื่อ จำกัด ขอบเขตในวิธีการขนาดใหญ่ได้เช่นกันแทนที่จะแบ่งออกเป็นวิธีการส่วนตัวหลาย ๆ วิธีซึ่งอาจไม่เกี่ยวข้องกับเมธอดคลาสอื่น
mmm

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

37

การประกาศตัวแปรโลคัลfinalจะไม่ส่งผลต่อการรวบรวมขยะหมายความว่าคุณไม่สามารถแก้ไขตัวแปรได้เท่านั้น ตัวอย่างข้างต้นของคุณไม่ควรรวบรวมในขณะที่คุณกำลังปรับเปลี่ยนตัวแปรซึ่งได้รับการทำเครื่องหมายtotalWeight finalในทางกลับกันการประกาศแบบดั้งเดิม ( doubleแทนDouble) finalจะช่วยให้ตัวแปรนั้นสามารถแทรกเข้าไปในรหัสการโทรได้ซึ่งอาจทำให้หน่วยความจำและประสิทธิภาพการทำงานดีขึ้น ใช้เมื่อคุณมีจำนวนpublic static final Stringsในชั้นเรียน

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


26

ไม่มันไม่เป็นความจริงอย่างชัดเจน

โปรดจำไว้finalว่าไม่ได้หมายถึงค่าคงที่ แต่หมายความว่าคุณไม่สามารถเปลี่ยนข้อมูลอ้างอิงได้

final MyObject o = new MyObject();
o.setValue("foo"); // Works just fine
o = new MyObject(); // Doesn't work.

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

Final ควรถือว่าเป็นข้อมูลเมตาที่มีประโยชน์สำหรับนักพัฒนาไม่ใช่เป็นการเพิ่มประสิทธิภาพคอมไพเลอร์


17

บางจุดที่ต้องล้าง:

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

  • ยังไม่มีการจัดสรรบนสแต็กใน Java

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


มีการจัดสรรบนสแต็ก (ของดั้งเดิมและการอ้างอิงถึงอ็อบเจ็กต์ในฮีป) ใน java: stackoverflow.com/a/8061692/32453 Java ต้องการอ็อบเจ็กต์ในการปิดเช่นเดียวกับคลาสที่ไม่ระบุชื่อ / แลมบ์ดาเพื่อให้เป็นขั้นสุดท้ายเช่นกัน แต่เปลี่ยน นั่นเป็นเพียงเพื่อลด "memory required / frame" / ลดความสับสนดังนั้นจึงไม่เกี่ยวข้องกับการรวบรวม ...
rogerdpack

11

ฉันไม่รู้เกี่ยวกับการใช้ตัวปรับแต่ง "ขั้นสุดท้าย" ในกรณีนี้หรือผลกระทบต่อ GC

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

ฉันใช้ไพรมารีแบบบรรจุกล่องเฉพาะเมื่อจำเป็นต้องใช้โดย API ที่มีอยู่หรือเมื่อฉันต้องการไพรเมอร์ที่เป็นโมฆะ


1
คุณพูดถูก ฉันต้องการเพียงตัวอย่างสั้น ๆ เพื่ออธิบายคำถามของฉัน
Goran Martinic

5

ตัวแปรสุดท้ายไม่สามารถเปลี่ยนแปลงได้หลังจากการกำหนดครั้งแรก (บังคับโดยคอมไพเลอร์)

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

คุณควรรู้ว่าขั้นสุดท้ายอนุญาตให้คอมไพเลอร์ตั้งสมมติฐานเกี่ยวกับสิ่งที่จะเพิ่มประสิทธิภาพ รหัสด้านในและไม่รวมรหัสที่ทราบว่าไม่สามารถเข้าถึงได้

final boolean debug = false;

......

if (debug) {
  System.out.println("DEBUG INFO!");
}

println จะไม่รวมอยู่ในรหัสไบต์


@Eugene ขึ้นอยู่กับตัวจัดการความปลอดภัยของคุณและคอมไพเลอร์อินไลน์ตัวแปรหรือไม่
Thorbjørn Ravn Andersen

ใช่ฉันแค่เป็นคนอวดดี ไม่มีอะไรมาก; ก็ให้คำตอบด้วยเช่นกัน
ยูจีน

4

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

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

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

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

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

บทความ:

ไอบีเอ็มในการเก็บขยะ: ประวัติศาสตร์ในสปอต JVMและประสิทธิภาพการทำงาน สิ่งเหล่านี้อาจใช้ไม่ได้อย่างสมบูรณ์อีกต่อไปเนื่องจากย้อนกลับไปในปี 2003/04 แต่ให้ข้อมูลเชิงลึกเกี่ยวกับ GC ที่อ่านง่าย

อาในการปรับแต่งการเก็บขยะ


3

GC ดำเนินการกับการอ้างอิงที่ไม่สามารถเข้าถึงได้ สิ่งนี้ไม่เกี่ยวข้องกับ "ขั้นสุดท้าย" ซึ่งเป็นเพียงการยืนยันการมอบหมายงานครั้งเดียว เป็นไปได้ไหมที่ GC ของ VM บางตัวสามารถใช้ "ขั้นสุดท้าย" ได้ ฉันไม่เห็นว่าเป็นอย่างไรหรือทำไม


3

finalบนตัวแปรและพารามิเตอร์โลคัลไม่มีความแตกต่างกับไฟล์คลาสที่สร้างดังนั้นจึงไม่ส่งผลต่อประสิทธิภาพรันไทม์ หากคลาสไม่มีคลาสย่อย HotSpot จะถือว่าคลาสนั้นเป็นคลาสสุดท้ายต่อไป (สามารถเลิกทำได้ในภายหลังหากคลาสที่แบ่งข้อสันนิษฐานนั้นถูกโหลด) ฉันเชื่อว่าfinalวิธีการนั้นเหมือนกับคลาสมาก finalในฟิลด์คงที่อาจทำให้ตัวแปรถูกตีความว่าเป็น "ค่าคงที่เวลาคอมไพล์" และการปรับให้เหมาะสมโดย javac บนพื้นฐานนั้น finalบนฟิลด์ช่วยให้ JVM มีอิสระในการละเว้นความสัมพันธ์ที่เกิดขึ้นก่อน


2

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

คำตอบสำหรับคำถามของคุณคือข้อที่สำคัญ


นั่นอาจเป็นความจริง แต่คอมไพเลอร์ยังคงสามารถใช้ข้อมูลขั้นสุดท้ายในระหว่างการวิเคราะห์กระแสข้อมูลได้

@WernerVanBelle คอมไพเลอร์รู้อยู่แล้วว่าตัวแปรถูกตั้งค่าเพียงครั้งเดียว ต้องทำการวิเคราะห์โฟลว์ข้อมูลอยู่แล้วเพื่อที่จะรู้ว่าตัวแปรอาจเป็นโมฆะไม่ได้ถูกกำหนดค่าเริ่มต้นก่อนการใช้งานเป็นต้นดังนั้น local finals จึงไม่เสนอข้อมูลใหม่ใด ๆ ให้กับคอมไพเลอร์
Matt Quigley

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

@WernerVanBelle ฉันทึ่งจริงๆคุณช่วยยกตัวอย่างได้ไหม? ฉันไม่เห็นว่าจะมีการกำหนดตัวแปรสุดท้ายให้กับตัวแปรที่ไม่ใช่ขั้นสุดท้ายที่คอมไพเลอร์ไม่รู้ได้อย่างไร คอมไพเลอร์รู้ว่าหากคุณมีตัวแปรที่ไม่ได้กำหนดค่าเริ่มต้นจะไม่อนุญาตให้คุณใช้ หากคุณพยายามกำหนดตัวแปรสุดท้ายภายในลูปคอมไพเลอร์จะไม่ยอมให้คุณ อะไรคือตัวอย่างที่ตัวแปรที่สามารถประกาศเป็นขั้นสุดท้าย แต่ไม่ใช่และคอมไพเลอร์ไม่สามารถรับประกันได้ว่าจะเป็นขั้นสุดท้าย ฉันสงสัยว่าตัวอย่างใด ๆ จะเป็นตัวแปรที่ไม่สามารถประกาศเป็นขั้นสุดท้ายได้ตั้งแต่แรก
Matt Quigley

หลังจากอ่านความคิดเห็นของคุณอีกครั้งฉันเห็นว่าตัวอย่างของคุณเป็นตัวแปรที่เริ่มต้นภายในบล็อกเงื่อนไข ตัวแปรเหล่านั้นไม่สามารถเป็นขั้นสุดท้ายได้ตั้งแต่แรกเว้นแต่ว่าเส้นทางเงื่อนไขทั้งหมดจะเริ่มต้นตัวแปรครั้งเดียว ดังนั้นคอมไพเลอร์จึงรู้เกี่ยวกับการประกาศดังกล่าวนั่นคือวิธีที่ช่วยให้คุณสามารถรวบรวมตัวแปรสุดท้ายที่เริ่มต้นในสองที่ที่แตกต่างกัน (คิดfinal int x; if (cond) x=1; else x=2;) คอมไพลเลอร์ที่ไม่มีคีย์เวิร์ดสุดท้ายจึงสามารถรับประกันได้ว่าตัวแปรจะสิ้นสุดหรือไม่
Matt Quigley

1

เมธอดและตัวแปรทั้งหมดสามารถถูกแทนที่ได้โดยค่าเริ่มต้นในคลาสย่อยหากเราต้องการบันทึกคลาสย่อยจากการลบล้างสมาชิกของซูเปอร์คลาสเราสามารถประกาศให้เป็นขั้นสุดท้ายโดยใช้คีย์เวิร์ดสุดท้าย สำหรับเช่น - การ final int a=10; final void display(){......} สร้างวิธีการขั้นสุดท้ายทำให้มั่นใจได้ว่าฟังก์ชันการทำงานที่กำหนดไว้ในซูเปอร์คลาสจะไม่มีการเปลี่ยนแปลงอีกต่อไป ในทำนองเดียวกันค่าของตัวแปรสุดท้ายไม่สามารถเปลี่ยนแปลงได้ ตัวแปรสุดท้ายมีพฤติกรรมเหมือนตัวแปรคลาส


1

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

สำหรับfinalช่องอินสแตนซ์เนื่องจากไม่สามารถแก้ไขได้ (ยกเว้นการสะท้อนแสง) จึงสามารถละอุปสรรคเหล่านี้ได้ และนี่ไม่ใช่แค่ทฤษฎีบริสุทธิ์

Shenandoah GCมีในทางปฏิบัติ (แม้ว่าจะไม่นาน ) และคุณสามารถทำได้เช่น:

-XX:+UnlockExperimentalVMOptions  
-XX:+UseShenandoahGC  
-XX:+ShenandoahOptimizeInstanceFinals

และจะมีการเพิ่มประสิทธิภาพในอัลกอริทึม GC ซึ่งจะทำให้เร็วขึ้นเล็กน้อย เนื่องจากจะไม่มีอุปสรรคขัดขวางfinalเนื่องจากไม่มีใครควรแก้ไขสิ่งเหล่านี้เลย ไม่ได้ผ่านการสะท้อนหรือ JNI


0

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


0

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


0

ครั้งเดียวที่ฉันต้องการประกาศตัวแปรท้องถิ่นเป็นขั้นสุดท้ายคือเมื่อ:

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

  • ผม ต้องการทำให้เป็นขั้นสุดท้าย (ตัวอย่างเช่นค่าบางอย่างที่ไม่ควร / ไม่ถูกแทนที่โดยไม่ได้ตั้งใจ)

พวกเขาช่วยในการเก็บขยะอย่างรวดเร็วหรือไม่?
AFAIK วัตถุจะกลายเป็นตัวเลือกของคอลเล็กชัน GC หากมีการอ้างอิงที่ชัดเจนเป็นศูนย์และในกรณีนั้นก็ไม่มีการรับประกันว่าจะถูกเก็บขยะทันที โดยทั่วไปการอ้างอิงที่รัดกุมจะถูกกล่าวว่าจะตายเมื่ออยู่นอกขอบเขตหรือผู้ใช้กำหนดให้เป็นการอ้างอิงที่ว่างเปล่าโดยชัดแจ้งดังนั้นการประกาศขั้นสุดท้ายหมายความว่าการอ้างอิงจะยังคงมีอยู่ต่อไปจนกว่าจะมีวิธีการ (เว้นแต่ขอบเขตจะแคบลงอย่างชัดเจนถึง บล็อกด้านในที่เฉพาะเจาะจง {}) เนื่องจากคุณไม่สามารถกำหนดตัวแปรสุดท้ายใหม่ได้ (กล่าวคือไม่สามารถกำหนดให้เป็น null ได้) ดังนั้นฉันคิดว่า wrt Garbage Collection 'ขั้นสุดท้าย' อาจทำให้เกิดความล่าช้าที่เป็นไปได้ที่ไม่ต้องการดังนั้นเราจึงต้องระมัดระวังเล็กน้อยในการกำหนดขอบเขตดังกล่าวเนื่องจากควบคุมว่าเมื่อไรที่พวกเขาจะกลายเป็นผู้สมัคร GC

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