การจัดสรรและการจัดการหน่วยความจำ Java เป็นหนึ่งในเทคโนโลยีหลักของ Java ก่อนหน้านี้เราได้แนะนำความรู้เกี่ยวกับการจัดการหน่วยความจำของ Java การรั่วไหลของหน่วยความจำและการรวบรวมขยะ Java วันนี้เราจะเข้าไปลึกเข้าไปในแกนชวาอีกครั้งและแนะนำรายละเอียดเกี่ยวกับความรู้เกี่ยวกับ Java ในการจัดสรรหน่วยความจำ โดยทั่วไปแล้ว Java จะเกี่ยวข้องกับพื้นที่ต่อไปนี้เมื่อจัดสรรหน่วยความจำ:
◆ลงทะเบียน: เราไม่สามารถควบคุมได้ในโปรแกรม
◆สแต็ค: เก็บประเภทข้อมูลพื้นฐานและการอ้างอิงไปยังวัตถุ แต่วัตถุนั้นไม่ได้เก็บไว้ในสแต็ก แต่ถูกเก็บไว้ในกอง (วัตถุที่ออกมาจากใหม่)
◆ฮีป: เก็บข้อมูลที่สร้างขึ้นโดยใช้ใหม่
◆โดเมนคงที่: สมาชิกคงที่เก็บไว้ในวัตถุที่กำหนดด้วยสแตติก
◆สระว่ายน้ำคงที่: ค่าคงที่ร้านค้า
◆ที่เก็บข้อมูลที่ไม่ใช่ RAM: พื้นที่เก็บข้อมูลถาวรเช่นฮาร์ดดิสก์
สแต็คในการจัดสรรหน่วยความจำ Java
ข้อมูลพื้นฐานบางประเภทที่กำหนดไว้ในฟังก์ชันและตัวแปรอ้างอิงของวัตถุทั้งหมดได้รับการจัดสรรในหน่วยความจำสแต็กของฟังก์ชั่น
เมื่อตัวแปรถูกกำหนดในบล็อกของรหัส Java จะจัดสรรพื้นที่หน่วยความจำสำหรับตัวแปรในสแต็ก เมื่อตัวแปรออกจากขอบเขต Java จะปล่อยพื้นที่หน่วยความจำที่จัดสรรไว้สำหรับตัวแปรโดยอัตโนมัติและสามารถใช้พื้นที่หน่วยความจำแยกกันได้ทันที ขนาดข้อมูลและวงจรชีวิตในสแต็กนั้นแน่นอนและข้อมูลนี้จะหายไปเมื่อไม่มีการอ้างอิงชี้ไปยังข้อมูล
กองในการจัดสรรหน่วยความจำ Java
หน่วยความจำฮีปใช้ในการจัดเก็บวัตถุและอาร์เรย์ที่สร้างขึ้นโดยใหม่ หน่วยความจำที่จัดสรรในกองได้รับการจัดการโดยเครื่องเก็บขยะอัตโนมัติของเครื่องเสมือนของ Java
หลังจากอาร์เรย์หรือวัตถุถูกสร้างขึ้นในฮีปตัวแปรพิเศษสามารถกำหนดได้ในสแต็กเพื่อให้ค่าของตัวแปรนี้ในสแต็กเท่ากับที่อยู่แรกของอาร์เรย์หรือวัตถุในหน่วยความจำฮีปและตัวแปรในสแต็กกลายเป็นตัวแปรอ้างอิงสำหรับอาร์เรย์หรือวัตถุ ตัวแปรอ้างอิงเทียบเท่ากับชื่อที่กำหนดให้กับอาร์เรย์หรือวัตถุ คุณสามารถใช้ตัวแปรอ้างอิงในสแต็กในโปรแกรมเพื่อเข้าถึงอาร์เรย์หรือวัตถุในกอง ตัวแปรอ้างอิงเทียบเท่ากับชื่อที่กำหนดให้กับอาร์เรย์หรือวัตถุ
ตัวแปรอ้างอิงเป็นตัวแปรธรรมดาซึ่งกำหนดไว้บนสแต็กเมื่อกำหนด ตัวแปรอ้างอิงจะถูกปล่อยออกมาหลังจากโปรแกรมทำงานนอกขอบเขต อาร์เรย์และคัดค้านตัวเองถูกจัดสรรในกอง แม้ว่าโปรแกรมจะทำงานนอกบล็อกรหัสซึ่งข้อความที่ใช้ใหม่เพื่อสร้างอาร์เรย์หรือวัตถุนั้นอยู่ในตำแหน่งหน่วยความจำที่ถูกครอบครองโดยอาร์เรย์และวัตถุเองก็จะไม่ถูกปล่อยออกมา อาร์เรย์และวัตถุกลายเป็นขยะเมื่อไม่มีตัวแปรอ้างอิงชี้ไปที่มันและไม่สามารถใช้งานได้ แต่ยังคงครอบครองพื้นที่หน่วยความจำ มันถูกรวบรวม (ปล่อย) โดยนักสะสมขยะในเวลาที่ไม่แน่นอน นี่คือเหตุผลที่ Java ใช้ความทรงจำมากขึ้น
ในความเป็นจริงตัวแปรในจุดสแต็กเป็นตัวแปรในหน่วยความจำฮีปซึ่งเป็นตัวชี้ใน Java!
กองและสแต็ค
กอง Java เป็นพื้นที่ข้อมูลรันไทม์ซึ่งวัตถุจัดสรรพื้นที่ วัตถุเหล่านี้ถูกจัดตั้งขึ้นผ่านคำแนะนำเช่นใหม่, Newarray, Anewarray และ MultiAnewarray พวกเขาไม่ต้องการให้รหัสโปรแกรมได้รับการเผยแพร่อย่างชัดเจน กองรับผิดชอบการรวบรวมขยะ ข้อได้เปรียบของกองคือสามารถจัดสรรขนาดหน่วยความจำแบบไดนามิกและอายุการใช้งานไม่จำเป็นต้องบอกกับคอมไพเลอร์ล่วงหน้าเพราะมันจัดสรรหน่วยความจำแบบไดนามิกเมื่อรันไทม์ นักสะสมขยะของ Java จะรวบรวมข้อมูลที่ไม่ได้ใช้โดยอัตโนมัติอีกต่อไป แต่ข้อเสียคือเพราะจำเป็นต้องจัดสรรหน่วยความจำแบบไดนามิกที่รันไทม์ความเร็วในการเข้าถึงจะช้าลง
ข้อได้เปรียบของสแต็กคือความเร็วในการเข้าถึงนั้นเร็วกว่ากองรองลงมารองจากการลงทะเบียนเท่านั้นและสามารถใช้ข้อมูลสแต็กได้ แต่ข้อเสียคือขนาดของข้อมูลและอายุการใช้งานในสแต็กจะต้องกำหนดและขาดความยืดหยุ่น สแต็กส่วนใหญ่เก็บข้อมูลตัวแปรพื้นฐานบางประเภท (int, สั้น, ยาว, ไบต์, ลอย, สอง, บูลีน, ถ่าน) และที่จับวัตถุ (การอ้างอิง)
คุณสมบัติพิเศษที่สำคัญมากของสแต็กคือข้อมูลที่มีอยู่ในสแต็กสามารถแชร์ได้ สมมติว่าเรากำหนดในเวลาเดียวกัน:
รหัส Java
int a = 3;
int b = 3;
คอมไพเลอร์ประมวลผลครั้งแรก int a = 3; ก่อนอื่นมันจะสร้างการอ้างอิงในสแต็กด้วยตัวแปร A แล้วค้นหาว่ามีค่า 3 ในสแต็กหรือไม่ หากไม่พบมันจะเก็บ 3 แล้วชี้ไปที่ 3 จากนั้นประมวลผล int b = 3; หลังจากสร้างตัวแปรอ้างอิงของ B เนื่องจากมีค่า 3 ในสแต็กแล้ว B จะถูกชี้ไปที่ 3 ด้วยวิธีนี้ A และ B ทั้งสองชี้ไปที่ 3 ในเวลาเดียวกัน
ในเวลานี้ถ้า A = 4 ถูกตั้งค่าอีกครั้ง; จากนั้นคอมไพเลอร์จะค้นหาอีกครั้งว่ามีค่า 4 ในสแต็กหรือไม่ ถ้าไม่เก็บ 4 และชี้ A ถึง 4; หากมีอยู่แล้วชี้ไปที่ที่อยู่นี้โดยตรง ดังนั้นการเปลี่ยนแปลงของมูลค่า A จะไม่ส่งผลกระทบต่อค่า b
ควรสังเกตว่าการแบ่งปันข้อมูลนี้แตกต่างจากการแบ่งปันการอ้างอิงจากวัตถุสองชิ้นที่ชี้ไปที่วัตถุหนึ่งในเวลาเดียวกันเพราะในกรณีนี้การปรับเปลี่ยนของ A จะไม่ส่งผลกระทบต่อ B มันจะทำโดยคอมไพเลอร์ซึ่งเอื้อต่อการประหยัดพื้นที่ ตัวแปรอ้างอิงวัตถุจะปรับเปลี่ยนสถานะภายในของวัตถุนี้และจะส่งผลกระทบต่อตัวแปรอ้างอิงวัตถุอื่น
รหัส Java
1.int i1 = 9;
2.int i2 = 9;
3.int i3 = 9;
4. สาธารณะคงที่ int int1 = 9;
5. สาธารณะคงที่ int2 = 9;
6. สาธารณะคงที่ int3 = 9;
สำหรับตัวแปรสมาชิกและตัวแปรท้องถิ่น: ตัวแปรสมาชิกเป็นตัวแปรที่กำหนดไว้ในวิธีและคลาส ตัวแปรท้องถิ่นเป็นตัวแปรที่กำหนดไว้ในวิธีการหรือบล็อกคำสั่ง ตัวแปรท้องถิ่นจะต้องเริ่มต้น
พารามิเตอร์อย่างเป็นทางการคือตัวแปรท้องถิ่นและข้อมูลของตัวแปรท้องถิ่นมีอยู่ในหน่วยความจำสแต็ก ตัวแปรท้องถิ่นในหน่วยความจำสแต็กหายไปเมื่อวิธีการหายไป
ตัวแปรสมาชิกจะถูกเก็บไว้ในวัตถุในกองและรวบรวมโดยนักสะสมขยะ
ในรหัสต่อไปนี้:
รหัส Java
วันเกิดชั้นเรียน {วันส่วนตัว เดือนเอกชน ปีเอกชน วันเกิดสาธารณะ (int d, int m, int y) {day = d; เดือน = M; ปี = y; } omit get, set method ……} การทดสอบคลาสสาธารณะ {โมฆะคงที่สาธารณะหลัก (สตริง args []) {int date = 9; ทดสอบทดสอบ = การทดสอบใหม่ (); test.change (วันที่); วันเกิด D1 = วันเกิดใหม่ (7,7,1970); } โมฆะสาธารณะ Change1 (int i) {i = 1234; -สำหรับรหัสข้างต้นวันที่เป็นตัวแปรท้องถิ่น i, d, m, y เป็นพารามิเตอร์ที่เป็นทางการทั้งหมดเป็นตัวแปรท้องถิ่นและวันเดือนและปีเป็นตัวแปรสมาชิก มาวิเคราะห์การเปลี่ยนแปลงระหว่างการดำเนินการรหัส:
1. วิธีหลักเริ่มดำเนินการ: วันที่ int = 9;
วันที่ตัวแปรท้องถิ่นประเภทพื้นฐานการอ้างอิงและค่าทั้งหมดมีอยู่ในสแต็ก
2. ทดสอบทดสอบ = การทดสอบใหม่ ();
การทดสอบเป็นการอ้างอิงวัตถุมีอยู่บนสแต็กและมีการทดสอบวัตถุ (ใหม่ ()) บนกอง
3. ทดสอบการเปลี่ยนแปลง (วันที่);
ฉันเป็นตัวแปรท้องถิ่นและมีการอ้างอิงและค่าอยู่ในสแต็ก เมื่อมีการเปลี่ยนแปลงวิธีการฉันจะหายไปจากสแต็ก
4. วันเกิด D1 = วันเกิดใหม่ (7,7,1970);
D1 เป็นการอ้างอิงวัตถุและมีอยู่ในสแต็ก วัตถุ (วันเกิดใหม่ ()) มีอยู่ในกองโดยที่ d, m, y เป็นตัวแปรท้องถิ่นที่เก็บไว้ในสแต็กและประเภทของพวกเขาเป็นประเภทฐานดังนั้นข้อมูลของพวกเขาจะถูกเก็บไว้ในสแต็ก วันเดือนปีเป็นตัวแปรสมาชิกและเก็บไว้ในกอง (วันเกิดใหม่ ()) เมื่อตัวสร้างวันเกิดถูกดำเนินการ, d, m, y จะหายไปจากสแต็ก
5. หลังจากวิธีการหลักถูกดำเนินการตัวแปรวันที่การทดสอบและการอ้างอิง D1 จะหายไปจากสแต็กและการทดสอบใหม่ () วันเกิดใหม่ () จะรอการรวบรวมขยะ
สระว่ายน้ำคงที่
พูลคงที่อ้างถึงข้อมูลบางอย่างที่กำหนดในช่วงระยะเวลาการรวบรวมและบันทึกไว้ในไฟล์. class ที่รวบรวม
นอกเหนือจากการมีค่าคงที่ (สุดท้าย) ของประเภทพื้นฐานต่างๆ (เช่น int, ยาว ฯลฯ ) และประเภทวัตถุ (เช่นสตริงและอาร์เรย์) ที่กำหนดไว้ในรหัสนอกจากนี้ยังมีการอ้างอิงเชิงสัญลักษณ์บางอย่างในรูปแบบข้อความเช่น::
◆ชื่อคลาสและอินเทอร์เฟซที่ผ่านการรับรอง
◆ชื่อและตัวบ่งชี้ของฟิลด์;
◆วิธีการและชื่อและคำอธิบาย
หากมีการสร้างช่วงเวลาการรวบรวม (กำหนดโดยตรงในคำพูดสองครั้ง) มันจะถูกเก็บไว้ในสระคงที่และหากสามารถกำหนดได้โดยระยะเวลาการวิ่ง (จากใหม่) มันจะถูกเก็บไว้ในกอง สำหรับสตริงที่มีค่าเท่ากับมีเพียงหนึ่งสำเนาในพูลคงที่และสำเนาหลายชุดในกอง
สตริงเป็นข้อมูลบรรจุภัณฑ์พิเศษ สามารถใช้:
รหัส Java
string str = สตริงใหม่ ("abc"); string str = "abc";มีสองรูปแบบที่จะสร้าง สิ่งแรกคือการใช้ใหม่ () เพื่อสร้างวัตถุใหม่ซึ่งจะถูกเก็บไว้ในกอง วัตถุใหม่ถูกสร้างขึ้นทุกครั้งที่เรียกว่า ประเภทที่สองคือการสร้างตัวแปร STR ไปยังวัตถุของคลาสสตริงในสแต็กก่อนจากนั้นใช้การอ้างอิงเชิงสัญลักษณ์เพื่อดูว่ามี "ABC" ในพูลคงที่สตริงหรือไม่ ถ้าไม่เก็บ "abc" ลงในพูลคงที่สตริงและให้ str ชี้ไปที่ "abc" หากมี "ABC" อยู่แล้วให้ชี้ไปที่ "ABC" โดยตรง
เมื่อเปรียบเทียบว่าค่าในคลาสมีค่าเท่ากันให้ใช้วิธี Equals () หรือไม่ เมื่อทดสอบว่าการอ้างอิงของคลาส wrapper ทั้งสองชี้ไปที่วัตถุเดียวกันให้ใช้ == และใช้ตัวอย่างด้านล่างเพื่อแสดงทฤษฎีข้างต้น
รหัส Java
string str1 = "abc"; string str2 = "abc"; system.out.println (str1 == str2); //จริง
จะเห็นได้ว่า str1 และ str2 ชี้ไปที่วัตถุเดียวกัน
รหัส Java
string str1 = สตริงใหม่ ("abc"); string str2 = สตริงใหม่ ("abc"); system.out.println (str1 == str2); // เท็จวิธีใหม่คือการสร้างวัตถุที่แตกต่างกัน สร้างทีละครั้ง
ดังนั้นในวิธีที่สองสตริง "ABC" หลายสายจึงถูกสร้างขึ้นและมีวัตถุเดียวในหน่วยความจำ วิธีการเขียนนี้มีประโยชน์และบันทึกพื้นที่หน่วยความจำ ในขณะเดียวกันก็สามารถปรับปรุงความเร็วในการทำงานของโปรแกรมในระดับหนึ่งเนื่องจาก JVM จะตัดสินใจโดยอัตโนมัติว่าจำเป็นต้องสร้างวัตถุใหม่ตามสถานการณ์จริงของข้อมูลในสแต็กหรือไม่ สำหรับรหัสของสตริง str = สตริงใหม่ ("ABC");, วัตถุใหม่ถูกสร้างขึ้นในฮีปโดยไม่คำนึงว่าค่าสตริงของพวกเขาเท่ากันหรือไม่ไม่ว่าจะเป็นสิ่งจำเป็นในการสร้างวัตถุใหม่ซึ่งจะเป็นการเพิ่มภาระในโปรแกรม
ในทางกลับกันหมายเหตุ: เมื่อเรากำหนดคลาสโดยใช้รูปแบบเช่น String str = "ABC";, เรามักจะรับมันเพื่อให้เราสร้างวัตถุ Str ของคลาสสตริง กังวลเกี่ยวกับกับดัก! วัตถุอาจไม่ได้ถูกสร้างขึ้น! และอาจจะชี้ไปที่วัตถุที่ถูกสร้างขึ้นก่อนหน้านี้ ผ่านวิธีใหม่ () เท่านั้นเราสามารถตรวจสอบให้แน่ใจว่ามีการสร้างวัตถุใหม่ทุกครั้ง
ตัวอย่างหลายประการของปัญหาการรวมสตริงคงที่
ตัวอย่างที่ 1:
รหัส Java
สตริง s0 = "kvill"; สตริง s1 = "kvill"; สตริง s2 = "kv" + "ป่วย"; system.out.println (s0 == s1); system.out.println (s0 == s2); ผลที่ได้คือ: Truetrue
การวิเคราะห์: ก่อนอื่นเราจำเป็นต้องรู้ว่าผลลัพธ์คือ Java จะทำให้แน่ใจว่าค่าคงที่สตริงมีเพียงหนึ่งสำเนา
เนื่องจาก S0 และ S1 ในตัวอย่างเป็นทั้งค่าคงที่สตริงจึงถูกกำหนดในช่วงระยะเวลาการรวบรวมดังนั้น S0 == S1 จึงเป็นจริง และ "KV" และ "ป่วย" ก็เป็นค่าคงที่สตริง เมื่อสตริงเชื่อมต่อกันด้วยค่าคงที่สตริงหลายค่ามันก็เป็นค่าคงที่สตริงดังนั้น S2 จึงถูกแยกวิเคราะห์เป็นค่าคงที่สตริงในช่วงระยะเวลาการรวบรวมดังนั้น S2 จึงอ้างอิงถึง "Kvill" ในสระคงที่ ดังนั้นเราจึงได้รับ S0 == S1 == S2;
ตัวอย่างที่ 2:
ตัวอย่าง:
รหัส Java
การวิเคราะห์: สตริงที่สร้างขึ้นด้วยสตริงใหม่ () ไม่ใช่ค่าคงที่และไม่สามารถกำหนดได้ในช่วงระยะเวลาการรวบรวมดังนั้นสตริงที่สร้างโดยสตริงใหม่ () จะไม่ถูกวางไว้ในสระคงที่พวกเขามีพื้นที่ที่อยู่ของตัวเอง
S0 ยังเป็นแอพพลิเคชั่นของ "Kvill" ในสระว่ายน้ำคงที่ S1 ไม่สามารถกำหนดได้ในช่วงระยะเวลาการรวบรวมดังนั้นจึงเป็นการอ้างอิงถึงวัตถุใหม่ "Kvill" ที่สร้างขึ้นเมื่อรันไทม์ S2 ไม่สามารถกำหนดได้ในช่วงระยะเวลาการรวบรวมเนื่องจากมีช่วงครึ่งหลังของสตริงใหม่ ("ป่วย") ดังนั้นจึงเป็นแอปพลิเคชันของวัตถุที่สร้างขึ้นใหม่ "Kvill"; หากคุณเข้าใจสิ่งเหล่านี้คุณจะรู้ว่าทำไมผลลัพธ์นี้จึงได้รับ
ตัวอย่างที่ 3:
รหัส Java
สตริง a = "a1"; สตริง b = "a" + 1; system.out.println ((a == b)); // result = true string a = "true"; string b = "a" + "true"; system.out.println ((a == b)); // result = true string a = "a3.4"; string b = "a" + 3.4; system.out.println ((a == b)); // result = true
การวิเคราะห์: สำหรับการเชื่อมต่อ JVM ของค่าคงที่สตริง JVM เพิ่มประสิทธิภาพการเชื่อมต่อ "+" ของสตริงคงที่กับค่าที่เชื่อมต่อหลังจากระยะเวลาการรวบรวมโปรแกรม ใช้ "A" + 1 เป็นตัวอย่าง หลังจากการปรับให้เหมาะสมโดยคอมไพเลอร์มันเป็น A1 อยู่แล้วในชั้นเรียน ในช่วงระยะเวลาการรวบรวมค่าของค่าคงที่สตริงจะถูกกำหนดดังนั้นผลลัพธ์สุดท้ายของโปรแกรมข้างต้นจึงเป็นจริง
ตัวอย่างที่ 4:
รหัส Java
String a = "ab"; string bb = "b"; string b = "a" + bb; system.out.println ((a == b)); // result = false
การวิเคราะห์: สำหรับการอ้างอิงสตริงใน JVM เนื่องจากมีการอ้างอิงสตริงในการเชื่อมต่อ " +" ของสตริงไม่สามารถกำหนดค่าอ้างอิงได้ในระหว่างระยะเวลาการรวบรวมโปรแกรมนั่นคือ "A" + BB ไม่สามารถปรับให้เหมาะสมโดยคอมไพเลอร์และจัดสรรแบบไดนามิกและกำหนดที่อยู่ใหม่ที่เชื่อมต่อกับ B ดังนั้นผลลัพธ์ของโปรแกรมข้างต้นจึงเป็นเท็จ
ตัวอย่างที่ 5:
รหัส Java
สตริง a = "ab"; สตริงสุดท้าย bb = "b"; สตริง b = "a" + bb; system.out.println ((a == b)); // result = true
การวิเคราะห์: ความแตกต่างเพียงอย่างเดียวระหว่าง [4] คือสตริง BB ได้รับการตกแต่งด้วยการปรับเปลี่ยนขั้นสุดท้าย สำหรับตัวแปรที่ได้รับการแก้ไขขั้นสุดท้ายมันจะถูกแยกวิเคราะห์เป็นสำเนาท้องถิ่นของค่าคงที่ในเวลาที่รวบรวมและเก็บไว้ในพูลคงที่ของตัวเองหรือฝังอยู่ในสตรีมไบต์ ดังนั้นในเวลานี้ผลกระทบของ "A" + BB และ "A" + "B" เหมือนกัน ดังนั้นผลลัพธ์ของโปรแกรมข้างต้นจึงเป็นจริง
ตัวอย่างที่ 6:
รหัส Java
สตริง a = "ab"; สตริงสุดท้าย bb = getBb (); สตริง b = "a" + bb; system.out.println ((a == b)); // result = falsePrivate สตริงคงที่ getBb () {return "b"; -การวิเคราะห์: การอ้างอิง JVM BB สำหรับสตริงและไม่สามารถกำหนดค่าของมันได้ในระหว่างระยะเวลาการรวบรวม หลังจากเรียกใช้วิธีการระหว่างรันไทม์โปรแกรมค่าส่งคืนของวิธีการและ "A" เชื่อมต่อแบบไดนามิกและที่อยู่จะถูกกำหนดให้กับ B ดังนั้นผลลัพธ์ของโปรแกรมข้างต้นจึงเป็นเท็จ
เกี่ยวกับสตริงไม่เปลี่ยนรูป
จากตัวอย่างข้างต้นเราสามารถค้นหาได้:
String S = "A" + "B" + "C";
มันเทียบเท่ากับสตริง s = "abc";
สตริง a = "a";
สตริง b = "b";
สตริง c = "c";
สตริง s = a + b + c;
สิ่งนี้แตกต่างผลลัพธ์สุดท้ายเท่ากับ:
รหัส Java
StringBuffer temp = new StringBuffer (); temp.append (a) .append (b) .append (c); string s = temp.toString ();
จากผลการวิเคราะห์ข้างต้นมันไม่ยากที่จะอนุมานว่าสตริงใช้ตัวดำเนินการเชื่อมต่อ (+) เพื่อวิเคราะห์เหตุผลสำหรับความไร้ประสิทธิภาพเช่นรหัสนี้:
รหัส Java
การทดสอบระดับสาธารณะ {โมฆะคงที่สาธารณะหลัก (สตริง args []) {string s = null; สำหรับ (int i = 0; i <100; i ++) {s+= "a"; -ทุกเวลา + เสร็จสิ้นวัตถุ StringBuilder จะถูกสร้างขึ้นแล้วผนวกมันและโยนมันทิ้ง ครั้งต่อไปที่ลูปมาถึงวัตถุสตริงจะถูกสร้างขึ้นใหม่แล้วผนวกสตริงและลูปจะเสร็จสมบูรณ์จนกว่าจะสิ้นสุด หากเราใช้วัตถุ StringBuilder โดยตรงเพื่อต่อท้ายเราสามารถบันทึกเวลา n - 1 ในการสร้างและทำลายวัตถุ ดังนั้นสำหรับแอปพลิเคชันที่ต้องใช้การต่อการเชื่อมต่อสตริงในลูปการดำเนินการภาคผนวกจะดำเนินการโดยทั่วไปโดยใช้วัตถุสตริงบัฟเฟอร์หรือสตริง
เนื่องจากลักษณะที่ไม่เปลี่ยนรูปของคลาสสตริงจึงมีหลายสิ่งที่จะพูดเกี่ยวกับเรื่องนี้ ตราบใดที่คุณทราบว่าอินสแตนซ์ของสตริงจะไม่เปลี่ยนแปลงเมื่อมันถูกสร้างขึ้นตัวอย่างเช่น: String str =” kv”+” ป่วย”+”“+” Ans”; มีค่าคงที่ 4 สตริงแรก“ KV” และ“ ป่วย” สร้าง“ Kvill” ในความทรงจำจากนั้น“ Kvill” และ“”” สร้าง“ Kvill” และ“” และในที่สุดก็สร้าง“ Kvill Ans” และกำหนดที่อยู่ของสตริงนี้เพราะสตริง
การใช้งานขั้นสุดท้ายและความเข้าใจในสตริง
รหัส Java
Final StringBuffer A = New StringBuffer ("111"); StringBuffer สุดท้าย B = New StringBuffer ("222"); a = B; // ประโยคนี้ไม่ได้รวบรวมจนกว่าจะเสร็จสิ้น Final StringBuffer A = New StringBuffer ("111"); A.Append ("222"); /// รวบรวมหลังจากเสร็จสิ้นจะเห็นได้ว่าสุดท้ายนั้นใช้ได้เฉพาะกับ "ค่า" ที่อ้างอิง (เช่นที่อยู่หน่วยความจำ) มันบังคับให้อ้างอิงไปยังชี้ไปที่วัตถุที่ชี้ไปในตอนแรก การเปลี่ยนการชี้จะทำให้เกิดข้อผิดพลาดในการรวบรวมเวลา สำหรับการเปลี่ยนแปลงในวัตถุที่ชี้ไปที่ขั้นสุดท้ายนั้นไม่รับผิดชอบ
สรุป
สแต็กใช้ในการจัดเก็บข้อมูลตัวแปรในท้องถิ่นของชนิดข้อมูลดั้งเดิมและการอ้างอิงไปยังวัตถุ (สตริงอาร์เรย์วัตถุ ฯลฯ ) แต่ไม่ได้จัดเก็บเนื้อหาวัตถุ
วัตถุที่สร้างขึ้นโดยใช้คำหลักใหม่จะถูกเก็บไว้ในกอง
สตริงเป็นคลาส wrapper พิเศษและการอ้างอิงจะถูกเก็บไว้ในสแต็กและเนื้อหาวัตถุจะต้องถูกกำหนดตามวิธีการสร้าง (พูลคงที่และฮีป) บางส่วนถูกสร้างขึ้นในเวลาคอมไพล์และเก็บไว้ในพูลคงที่สตริงในขณะที่บางส่วนถูกสร้างขึ้นเมื่อรันไทม์เท่านั้น ใช้คำหลักใหม่และเก็บไว้ในกอง
บทความข้างต้นพูดสั้น ๆ เกี่ยวกับความแตกต่างระหว่างการจัดสรรหน่วยความจำ Java+ และตำแหน่งที่เก็บข้อมูลตัวแปรเป็นเนื้อหาทั้งหมดที่ฉันแบ่งปันกับคุณ ฉันหวังว่าคุณจะให้ข้อมูลอ้างอิงและฉันหวังว่าคุณจะสนับสนุน wulin.com มากขึ้น