1. แนวคิดพื้นฐาน
โปรแกรม Java แต่ละรายการจะสร้างกระบวนการ Java แต่ละกระบวนการ Java อาจมีเธรดอย่างน้อยหนึ่งเธรด กระบวนการ Java แต่ละกระบวนการสอดคล้องกับอินสแตนซ์ JVM ที่ไม่ซ้ำกันแต่ละอินสแตนซ์ JVM แต่ละอินสแตนซ์สอดคล้องกับกองและแต่ละเธรดมีสแต็กส่วนตัวของตัวเอง อินสแตนซ์ทั้งหมดของคลาส (นั่นคือวัตถุ) หรืออาร์เรย์ (หมายถึงอาร์เรย์ไม่ใช่การอ้างอิง) ที่สร้างโดยกระบวนการจะถูกวางไว้ในกองและแบ่งปันโดยเธรดทั้งหมดของกระบวนการ หน่วยความจำฮีปที่จัดสรรใน Java จะเริ่มต้นโดยอัตโนมัตินั่นคือเมื่อจัดสรรหน่วยความจำให้กับวัตถุตัวแปรในวัตถุจะเริ่มต้น แม้ว่าพื้นที่เก็บข้อมูลของวัตถุทั้งหมดใน Java จะถูกจัดสรรในฮีปการอ้างอิงไปยังวัตถุนี้จะถูกจัดสรรในสแต็กนั่นคือเมื่อวัตถุถูกสร้างขึ้นหน่วยความจำจะถูกจัดสรรในกองและสแต็ก หน่วยความจำที่จัดสรรในฮีปจะเก็บวัตถุที่สร้างขึ้นเองในขณะที่หน่วยความจำที่จัดสรรในสแต็กจะเก็บเฉพาะการอ้างอิงไปยังวัตถุฮีป เมื่อตัวแปรท้องถิ่นใหม่ออกมาพื้นที่จะถูกจัดสรรในพื้นที่สแต็กและพื้นที่กอง เมื่อวงจรชีวิตตัวแปรท้องถิ่นสิ้นสุดลงพื้นที่สแต็กจะถูกรีไซเคิลทันทีและพื้นที่พื้นที่ฮีปกำลังรอให้ GC รีไซเคิล
แนวคิดเฉพาะ: ความทรงจำของ JVM สามารถแบ่งออกเป็นสามพื้นที่: กองซ้อนและพื้นที่วิธีการ (วิธีการที่เรียกว่าพื้นที่คงที่):
พื้นที่สแต็ก:
1. ทั้งหมดที่เก็บไว้เป็นวัตถุและแต่ละวัตถุมีข้อมูลที่สอดคล้องกับมัน (วัตถุประสงค์ของคลาสคือการได้รับคำแนะนำการดำเนินการ);
2.JVM มีพื้นที่เพียงหนึ่งกอง (กอง) และแบ่งปันโดยเธรดทั้งหมด กองไม่ได้เก็บประเภทพื้นฐานและการอ้างอิงวัตถุ แต่มีเพียงวัตถุเท่านั้นและอาร์เรย์เท่านั้น
พื้นที่สแต็ก:
1. แต่ละเธรดมีพื้นที่สแต็กซึ่งบันทึกการอ้างอิงไปยังประเภทข้อมูลพื้นฐานและวัตถุที่กำหนดเองเท่านั้น
2. ข้อมูล (ประเภทดั้งเดิมและการอ้างอิงวัตถุ) ในแต่ละสแต็คเป็นส่วนตัวและไม่สามารถเข้าถึงได้โดยสแต็กอื่น ๆ
3. สแต็กแบ่งออกเป็น 3 ส่วน: พื้นที่ตัวแปรประเภทพื้นฐานบริบทสภาพแวดล้อมการดำเนินการและพื้นที่คำสั่งการดำเนินงาน (การจัดเก็บคำแนะนำการดำเนินการ);
พื้นที่วิธีการ (พื้นที่คงที่):
1. แชร์โดยกระทู้ทั้งหมด พื้นที่วิธีการประกอบด้วยคลาสทั้งหมด (คลาสหมายถึงรหัสดั้งเดิมของคลาสเพื่อสร้างวัตถุคลาสรหัสของคลาสจะต้องโหลดลงในพื้นที่เมธอดและเริ่มต้น) และตัวแปรคงที่
2. พื้นที่วิธีการมีองค์ประกอบที่ไม่ซ้ำกันในโปรแกรมทั้งหมดเช่นคลาสและตัวแปรคงที่
2. ตัวอย่างการสาธิต
appmain.java
AppMain คลาสสาธารณะ // เมื่อทำงาน JVM จะวางรหัส AppMain ทั้งหมดลงในพื้นที่เมธอด {โมฆะคงที่สาธารณะหลัก (สตริง [] args) // วิธีการหลักนั้นถูกวางไว้ในพื้นที่วิธีการ {ตัวอย่าง test1 = ตัวอย่างใหม่ ("ทดสอบ 1"); // test1 เป็นข้อมูลอ้างอิงดังนั้นใส่ในพื้นที่สแต็กตัวอย่างเป็นวัตถุที่กำหนดเองซึ่งควรวางไว้ในกอง ตัวอย่าง test2 = ตัวอย่างใหม่ ("ทดสอบ 2"); test1.printName (); test2.printName (); }} ตัวอย่างคลาสสาธารณะ // เมื่อทำงาน JVM จะใส่ข้อมูลทั้งหมดของ AppMain ลงในพื้นที่เมธอด { /** ชื่อตัวอย่าง* /ชื่อสตริงส่วนตัว; // หลังจากอินสแตนซ์ตัวอย่างใหม่การอ้างอิงชื่อจะถูกวางไว้ในพื้นที่สแต็กชื่อวัตถุสตริงที่สอดคล้องกันจะถูกวางไว้ในฮีป/** ตัวสร้าง*/ตัวอย่างสาธารณะ (ชื่อสตริง) {this .Name = NAME; } /** เอาต์พุต* /โมฆะสาธารณะ printName () // เมื่อไม่มีวัตถุวิธีการพิมพ์จะถูกวางไว้ในพื้นที่วิธีการพร้อมกับคลาสตัวอย่าง {system.out.println (ชื่อ); -เมื่อเรียกใช้โปรแกรมก่อนอื่นให้เริ่มกระบวนการเสมือนจริงของ Java ขั้นตอนนี้จะพบไฟล์ AppMain.Class จาก classPath อ่านข้อมูลไบนารีในไฟล์จากนั้นจัดเก็บข้อมูลคลาสของคลาส AppMain ในพื้นที่วิธีการของพื้นที่ข้อมูลรันไทม์ นี่คือกระบวนการโหลดของคลาส AppMain
ถัดไปเครื่องเสมือน Java จะตั้งค่า bytecode ของวิธีการหลัก () ของคลาส AppMain ในพื้นที่เมธอดและเริ่มดำเนินการตามคำแนะนำ คำสั่งแรกของวิธีการหลัก () นี้คือ:
การคัดลอกรหัสมีดังนี้:
ตัวอย่างทดสอบ 1 = ตัวอย่างใหม่ ("test1");
กระบวนการดำเนินการของคำสั่งนี้:
1. เครื่องเสมือน Java พบข้อมูลประเภทของคลาสตัวอย่างในพื้นที่วิธีการ แต่ไม่พบเนื่องจากคลาสตัวอย่างไม่ได้ถูกโหลดเข้าไปในพื้นที่วิธีการ (สามารถเห็นได้ที่นี่ว่าชั้นเรียนภายในใน Java มีอยู่แยกกันและในตอนแรก เครื่องเสมือน Java จะโหลดคลาสตัวอย่างทันทีและจัดเก็บข้อมูลประเภทคลาสตัวอย่างในพื้นที่เมธอด
2. เครื่องเสมือน Java ก่อนจัดสรรหน่วยความจำสำหรับอินสแตนซ์ตัวอย่างใหม่ในพื้นที่ฮีปและเก็บที่อยู่หน่วยความจำในพื้นที่วิธีการที่ข้อมูลประเภทคลาสตัวอย่างถูกเก็บไว้ในหน่วยความจำของอินสแตนซ์ตัวอย่าง
3. ในกระบวนการ JVM แต่ละเธรดจะมีวิธีการเรียกใช้สแต็กซึ่งใช้ในการติดตามชุดของกระบวนการเรียกใช้วิธีการในระหว่างการทำงานของเธรด แต่ละองค์ประกอบในสแต็กเรียกว่าเฟรมสแต็ก เมื่อใดก็ตามที่เธรดเรียกวิธีการเฟรมใหม่จะถูกผลักเข้าไปในสแต็กวิธีการ เฟรมที่นี่ใช้เพื่อจัดเก็บพารามิเตอร์ของวิธีตัวแปรท้องถิ่นและข้อมูลชั่วคราวระหว่างการดำเนินการ
4. test1 ก่อน "=" เป็นตัวแปร (การอ้างอิงไปยังวัตถุตัวอย่าง) ที่กำหนดไว้ในวิธีการหลัก () ดังนั้นมันจะถูกเพิ่มลงในสแต็กการเรียกใช้วิธี Java ของเธรดหลักที่ดำเนินการวิธีการหลัก () และ "=" จะชี้ตัวแปร test1 นี้ไปยังอินสแตนซ์ตัวอย่างในพื้นที่ฮีป
5. JVM ยังคงสร้างอินสแตนซ์ตัวอย่างอื่นในพื้นที่ฮีปและเพิ่มตัวแปร test2 ลงในสแต็กการเรียกวิธีการของวิธีหลักซึ่งชี้ไปที่อินสแตนซ์ตัวอย่างใหม่ที่สร้างขึ้นในพื้นที่ฮีป
6. JVM ดำเนินการวิธี printName () ของพวกเขาในทางกลับกัน เมื่อ Java Virtual Machine ดำเนินการเมธอด test1.printName () เครื่องเสมือน Java จะหาตัวอย่างอินสแตนซ์ตัวอย่างในพื้นที่ฮีปตามการอ้างอิงที่จัดขึ้นโดยตัวแปรท้องถิ่น test1 จากนั้นหาข้อมูลประเภทคลาสตัวอย่างในวิธีการอ้างอิงที่จัดขึ้นโดยอินสแตนซ์ตัวอย่าง
iii. แยกแยะ
ความแตกต่างระหว่างกองและสแต็คในภาษาชวา:
1. สแต็คและกองเป็นทั้งสองสถานที่ที่ใช้โดย Java เพื่อจัดเก็บข้อมูลใน RAM ซึ่งแตกต่างจาก C ++, Java จัดการกองซ้อนและกองโดยอัตโนมัติและโปรแกรมเมอร์ไม่สามารถตั้งค่าสแต็คหรือกองโดยตรงได้
2. ข้อดีของสแต็กคือความเร็วในการเข้าถึงนั้นเร็วกว่าฮีปรองจากการลงทะเบียนที่อยู่ในซีพียูโดยตรง แต่ข้อเสียคือขนาดของข้อมูลและอายุการใช้งานในสแต็กจะต้องกำหนดและขาดความยืดหยุ่น นอกจากนี้ยังสามารถใช้ข้อมูลสแต็กได้ (ดูคำแนะนำด้านล่างสำหรับรายละเอียด) ข้อได้เปรียบของกองคือมันสามารถจัดสรรขนาดหน่วยความจำแบบไดนามิกและอายุการใช้งานไม่จำเป็นต้องบอกกับคอมไพเลอร์ล่วงหน้า นักสะสมขยะของ Java จะรวบรวมข้อมูลที่ไม่ได้ใช้โดยอัตโนมัติอีกต่อไป แต่ข้อเสียคือหน่วยความจำจะต้องได้รับการจัดสรรแบบไดนามิกที่รันไทม์ความเร็วในการเข้าถึงจะช้าลง
2 ประเภทข้อมูลใน Java:
หนึ่งคือประเภทดั้งเดิมที่มี 8 หมวดหมู่คือ int, สั้น, ยาว, ยาว, ไบต์, ลอย, สอง, บูลีน, ถ่าน (โปรดทราบว่าไม่มีประเภทพื้นฐานของสตริง) คำจำกัดความประเภทนี้ถูกกำหนดโดยแบบฟอร์มเช่น int a = 3; ยาว b = 255L; และเรียกว่าตัวแปรอัตโนมัติ ตัวแปรอัตโนมัติมีค่าตัวอักษรไม่ใช่อินสแตนซ์ของคลาสนั่นคือพวกเขาไม่ได้อ้างอิงถึงคลาสและไม่มีชั้นเรียนที่นี่ ตัวอย่างเช่น int a = 3; นี่คือการอ้างอิงที่ชี้ไปที่ประเภท int ชี้ไปที่ค่าตัวอักษรที่ 3 เนื่องจากขนาดและอายุการใช้งานของข้อมูลตัวอักษรเหล่านี้ค่าตัวอักษรเหล่านี้ถูกกำหนดไว้อย่างสม่ำเสมอในบล็อกโปรแกรมและค่าฟิลด์จะหายไปหลังจากบล็อกของโปรแกรมออก) และมีอยู่ในสแต็ก
สแต็กมีคุณสมบัติที่สำคัญมาก: ข้อมูลที่มีอยู่ในสแต็กสามารถแชร์ได้ สมมติว่าเรากำหนดในเวลาเดียวกัน: int a = 3; int b = 3; คอมไพเลอร์ประมวลผลครั้งแรก int a = 3; ก่อนอื่นมันจะสร้างการอ้างอิงด้วยตัวแปร A ในสแต็กจากนั้นดูว่ามีที่อยู่ที่มีค่าตามตัวอักษร 3 หรือไม่หากไม่พบมันจะเปิดที่อยู่ด้วยค่าตัวอักษร 3 แล้วชี้ไปที่ที่อยู่ 3 จากนั้นประมวลผล int b = 3; หลังจากสร้างตัวแปรอ้างอิงของ B เนื่องจากมีค่าตามตัวอักษร 3 ในสแต็กแล้ว B จะชี้ไปที่ที่อยู่ของ 3 ด้วยวิธีนี้ A และ B ทั้งสองชี้ไปที่ 3 ในเวลาเดียวกัน
การอ้างอิงถึงค่าตัวอักษรนี้แตกต่างจากของวัตถุคลาส สมมติว่าการอ้างอิงของวัตถุคลาสสองตัวชี้ไปที่วัตถุในเวลาเดียวกันหากตัวแปรอ้างอิงวัตถุหนึ่งเปลี่ยนสถานะภายในของวัตถุตัวแปรอ้างอิงวัตถุอื่น ๆ จะสะท้อนการเปลี่ยนแปลงนี้ทันที แต่การปรับเปลี่ยนค่าผ่านการอ้างอิงตามตัวอักษรจะไม่ทำให้ค่าอื่นมีการเปลี่ยนแปลงตามนั้น ดังในตัวอย่างข้างต้นหลังจากเรากำหนดค่าของ A และ B ให้ A = 4; จากนั้น B จะไม่เท่ากับ 4 หรือเท่ากับ 3 ภายในคอมไพเลอร์เมื่อพบ A = 4 มันจะค้นหาอีกครั้งว่ามีค่าตัวอักษร 4 ในสแต็ก ถ้าไม่เปิดที่อยู่อีกครั้งเพื่อจัดเก็บค่า 4; หากมีอยู่แล้วชี้ไปที่ที่อยู่นี้โดยตรง ดังนั้นการเปลี่ยนแปลงของมูลค่า A จะไม่ส่งผลกระทบต่อค่า b
ประเภทอื่นคือข้อมูลคลาสบรรจุภัณฑ์เช่นจำนวนเต็มสตริงคู่ ฯลฯ ที่ห่อหุ้มชนิดข้อมูลพื้นฐานที่สอดคล้องกัน ข้อมูลคลาสทั้งหมดเหล่านี้มีอยู่ในกอง Java ใช้คำสั่งใหม่ () เพื่อแสดงคอมไพเลอร์และสร้างขึ้นอย่างมีชีวิตชีวาตามความจำเป็นในการรันไทม์ดังนั้นจึงมีความยืดหยุ่นมากขึ้น แต่ข้อเสียคือต้องใช้เวลามากขึ้น
4. สรุป
โครงสร้างการจัดสรรหน่วยความจำ Java ยังคงชัดเจนมาก หากคุณต้องการที่จะเข้าใจอย่างละเอียดคุณสามารถตรวจสอบหนังสือที่เกี่ยวข้องกับ JVM ใน Java สิ่งที่ลำบากที่สุดเกี่ยวกับการจัดสรรหน่วยความจำคือวัตถุสตริง เนื่องจากลักษณะพิเศษของโปรแกรมเมอร์จำนวนมากมีแนวโน้มที่จะสับสน ฉันจะอธิบายรายละเอียดในบทความถัดไป