การจัดสรรแบบคงที่ใน java - heap, stack และการสร้างแบบถาวร


117

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

  1. คลาส (โหลดโดย classloaders) ไปในพื้นที่พิเศษบนฮีป: การสร้างแบบถาวร
  2. ข้อมูลทั้งหมดที่เกี่ยวข้องกับคลาสเช่นชื่อคลาสอาร์เรย์อ็อบเจ็กต์ที่เกี่ยวข้องกับคลาสอ็อบเจ็กต์ภายในที่ใช้โดย JVM (เช่น java / lang / Object) และข้อมูลการปรับให้เหมาะสมจะเข้าสู่พื้นที่การสร้างแบบถาวร
  3. ตัวแปรสมาชิกคงที่ทั้งหมดจะถูกเก็บไว้ในพื้นที่การสร้างแบบถาวรอีกครั้ง
  4. วัตถุไปกองที่แตกต่างกัน: คนรุ่นใหม่
  5. มีเพียงหนึ่งสำเนาของแต่ละวิธีต่อคลาสเท่านั้นไม่ว่าจะเป็นวิธีการแบบคงที่หรือไม่คงที่ สำเนานั้นใส่ไว้ในพื้นที่การสร้างแบบถาวร สำหรับวิธีการที่ไม่คงที่พารามิเตอร์และตัวแปรโลคัลทั้งหมดจะเข้าสู่สแต็กและเมื่อใดก็ตามที่มีการเรียกใช้เมธอดนั้นอย่างเป็นรูปธรรมเราจะได้สแต็กเฟรมใหม่ที่เชื่อมโยงกับมัน ฉันไม่แน่ใจว่าตัวแปรโลคัลของวิธีคงที่ถูกเก็บไว้ที่ไหน พวกเขาอยู่ในกองของการสร้างแบบถาวรหรือไม่? หรือเพียงข้อมูลอ้างอิงถูกเก็บไว้ในพื้นที่การสร้างแบบถาวรและสำเนาจริงอยู่ที่อื่น (ที่ไหน?)
  6. ฉันยังไม่แน่ใจด้วยว่าประเภทการส่งคืนของเมธอดจะถูกเก็บไว้ที่ใด
  7. หากออบเจ็กต์ (ในรุ่นเยาว์) จำเป็นต้องใช้สมาชิกแบบคงที่ (ในรุ่นถาวร) พวกเขาจะได้รับการอ้างอิงถึงสมาชิกแบบคงที่ && พวกเขาจะได้รับพื้นที่หน่วยความจำเพียงพอที่จะจัดเก็บประเภทการส่งคืนของวิธีการ ฯลฯ

ขอบคุณสำหรับสิ่งนี้!

คำตอบ:


152

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

หากคุณต้องการการยืนยันคำตอบที่ชัดเจนคุณต้องดาวน์โหลดซอร์สโค้ด OpenJDK ... และทำการค้นคว้าของคุณเองโดยการอ่านและทำความเข้าใจซอร์สโค้ด การถามคำถามเกี่ยวกับ SO หรือการอ่านบทความบนเว็บแบบสุ่มไม่ใช่เทคนิคการวิจัยทางวิชาการที่ดี

ต้องบอกว่า ...

... คำถามของฉันคือซันโดยเฉพาะ

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

คำตอบด้านล่างนี้ใช้กับ Oracle Hotspot และ OpenJDK และอาจใช้กับรุ่นอื่น ๆ ส่วนใหญ่เช่นกัน ... รวมถึง GraalVM

1) คลาส (โหลดโดย classloaders) ไปในพื้นที่พิเศษบนฮีป: การสร้างแบบถาวร

ก่อนหน้า Java 8 ใช่

ตั้งแต่ Java 8 พื้นที่ PermGen ถูกแทนที่ด้วย Metaspace คลาสที่โหลดและคอมไพล์ JIT ไปที่นั่นแล้ว PermGen ไม่มีแล้ว

2) ข้อมูลทั้งหมดที่เกี่ยวข้องกับคลาสเช่นชื่อคลาสอาร์เรย์อ็อบเจ็กต์ที่เกี่ยวข้องกับคลาสอ็อบเจ็กต์ภายในที่ JVM ใช้ (เช่น java / lang / Object) และข้อมูลการปรับให้เหมาะสมจะเข้าสู่พื้นที่การสร้างแบบถาวร

มากหรือน้อยใช่ ฉันไม่แน่ใจว่าคุณหมายถึงอะไรจากสิ่งเหล่านั้น ฉันคาดเดาว่า "ออบเจ็กต์ภายในที่ใช้โดย JVM (เช่น java / lang / Object)" หมายถึงตัวบอกคลาส JVM ภายใน

3) ตัวแปรสมาชิกคงที่ทั้งหมดจะถูกเก็บไว้ในพื้นที่การสร้างแบบถาวรอีกครั้ง

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

4) วัตถุไปกองที่แตกต่างกัน: คนรุ่นใหม่

ไม่จำเป็น. วัตถุขนาดใหญ่อาจถูกจัดสรรให้กับรุ่นที่ครอบครองโดยตรง

5) มีเพียงหนึ่งสำเนาของแต่ละวิธีต่อคลาสคือวิธีคงที่หรือไม่คงที่ สำเนานั้นใส่ไว้ในพื้นที่การสร้างแบบถาวร

สมมติว่าคุณอ้างถึงรหัสของวิธีการแล้ว AFAIK ใช่ มันอาจจะซับซ้อนกว่าเล็กน้อย ตัวอย่างเช่นรหัสอาจมีอยู่ในรูปแบบ bytecode และ / หรือเนทีฟโค้ดในช่วงเวลาที่ต่างกันในช่วงชีวิตของ JVM

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

ใช่.

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

ไม่ได้มีการจัดเก็บไว้ในสแต็กเช่นเดียวกับตัวแปรโลคัลในวิธีการไม่คงที่

6) ฉันไม่แน่ใจด้วยว่าประเภทการส่งคืนของวิธีการเก็บไว้ที่ไหน

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

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

นั่นไม่ถูกต้อง (หรืออย่างน้อยคุณก็ไม่ได้แสดงออกอย่างชัดเจน)

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

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

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

  • ไม่ว่าในกรณีใดผู้เรียกจะต้องจัดสรรพื้นที่เพื่อเก็บอ็อบเจ็กต์ / อาร์เรย์ที่ส่งคืนโดยวิธีการ ใน Java อ็อบเจ็กต์และอาร์เรย์จะถูกส่งกลับโดยใช้ความหมาย pass-by-value เสมอ ... แต่ค่าที่ส่งกลับเป็นการอ้างอิงอ็อบเจ็กต์หรืออาร์เรย์


สำหรับข้อมูลเพิ่มเติมโปรดดูแหล่งข้อมูลเหล่านี้:

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