ตัวอย่างในบทความนี้อธิบายวิธีการคำนวณ (หรือประมาณ) จำนวนหน่วยความจำที่อ็อบเจ็กต์ Java ครอบครอง แบ่งปันกับทุกคนสำหรับการอ้างอิงของคุณ การวิเคราะห์เฉพาะมีดังนี้:
โดยปกติแล้ว เราจะพูดถึงการใช้หน่วยความจำฮีปในบริบทของ "กรณีทั่วไป" ไม่รวมสองสถานการณ์ต่อไปนี้:
ในบางกรณี JVM จะไม่ใส่ Object ลงในฮีปเลย ตัวอย่างเช่น: ตามหลักการแล้ว มีวัตถุภายในเธรดขนาดเล็กอยู่บนสแต็ก ไม่ใช่ในฮีป
จำนวนหน่วยความจำที่วัตถุครอบครองนั้นขึ้นอยู่กับสถานะปัจจุบันของวัตถุ ตัวอย่างเช่น ไม่ว่าการล็อคการซิงโครไนซ์ของออบเจ็กต์มีผลหรือไม่ หรือออบเจ็กต์กำลังถูกรีไซเคิลหรือไม่
ก่อนอื่นเรามาดูกันว่า Object เดียวจะมีลักษณะเป็นอย่างไรในฮีป
ในฮีป แต่ละออบเจ็กต์ประกอบด้วยสี่ช่อง (A, B, C และ D) มาอธิบายแต่ละช่องด้านล่าง:
ตอบ: ส่วนหัวของออบเจ็กต์ ซึ่งใช้พื้นที่น้อยมากและเป็นการแสดงข้อมูลเกี่ยวกับสถานะปัจจุบันของออบเจ็กต์
B: พื้นที่ที่ถูกครอบครองโดยฟิลด์ประเภทพื้นฐาน (ฟิลด์ดั้งเดิมหมายถึง int, บูลีน, แบบสั้น ฯลฯ )
C: พื้นที่ว่างที่ถูกครอบครองโดยฟิลด์ประเภทการอ้างอิง (ฟิลด์ประเภทการอ้างอิงอ้างถึงการอ้างอิงไปยังวัตถุอื่น ๆ การอ้างอิงแต่ละครั้งจะใช้พื้นที่ 4 ไบต์)
D: เนื้อที่ของฟิลเลอร์ (ฟิลเลอร์คืออะไรจะอธิบายในภายหลัง)
ด้านล่างนี้เราจะอธิบาย A, B, C และ D ทีละรายการ
ตอบ: ส่วนหัวของวัตถุ
ในหน่วยความจำ พื้นที่ทั้งหมดที่ครอบครองโดยแต่ละวัตถุไม่เพียงแต่รวมถึงพื้นที่ที่จำเป็นสำหรับตัวแปรที่ประกาศภายในวัตถุเท่านั้น แต่ยังรวมถึงข้อมูลเพิ่มเติมบางอย่าง เช่น ส่วนหัวของวัตถุและตัวเติม หน้าที่ของ "ส่วนหัวของออบเจ็กต์" คือการบันทึกชื่ออินสแตนซ์, ID และสถานะอินสแตนซ์ของออบเจ็กต์ (เช่น อินสแตนซ์ปัจจุบัน "เข้าถึงได้" หรือไม่ หรือสถานะของการล็อกปัจจุบัน เป็นต้น)
ในเวอร์ชัน JVM ปัจจุบัน (Hotspot) จำนวนไบต์ที่ "ส่วนหัวของวัตถุ" ครอบครองจะเป็นดังนี้:
วัตถุธรรมดาที่มีขนาด 8 ไบต์
อาร์เรย์ มีขนาด 12 ไบต์ รวมถึงวัตถุธรรมดา 8 ไบต์ + 4 ไบต์ (ความยาวอาร์เรย์)
B: ประเภทพื้นฐาน
บูลีนและไบต์ครอบครอง 1 ไบต์, char และ short ครอบครอง 2 ไบต์, int และ float ครอบครอง 4 ไบต์, long และ double ครอบครอง 8 ไบต์
C: ประเภทอ้างอิง
ประเภทการอ้างอิงแต่ละประเภทมีขนาด 4 ไบต์
D: ฟิลเลอร์
ใน Hotspot พื้นที่ทั้งหมดที่ครอบครองโดยแต่ละวัตถุจะถูกคำนวณเป็นผลคูณของ 8 เมื่อพื้นที่ทั้งหมดที่วัตถุครอบครอง (ส่วนหัวของวัตถุ + ตัวแปรที่ประกาศ) น้อยกว่าผลคูณของ 8 พื้นที่นั้นจะถูกเติมโดยอัตโนมัติ อย่างไรก็ตาม ช่องว่างที่เต็มไปเหล่านี้สามารถเรียกว่า "ฟิลเลอร์" ได้ ลองดูตัวอย่างที่เฉพาะเจาะจง:
วัตถุว่าง (โดยไม่มีการประกาศตัวแปรใด ๆ ) ครอบครอง 8 ไบต์ -> ส่วนหัวของวัตถุครอบครอง 8 ไบต์
คลาสที่ประกาศตัวแปรประเภทบูลีนเพียงตัวเดียวจะใช้เวลา 16 ไบต์ -> ส่วนหัวของวัตถุ (8 ไบต์) + บูลีน (1 ไบต์) + ตัวเติม (7 ไบต์)
คลาสที่ประกาศตัวแปรประเภทบูลีน 8 ตัวใช้เวลา 16 ไบต์ -> ส่วนหัวของวัตถุ (8 ไบต์) + บูลีน (1 ไบต์) * 8
ตัวอย่างข้างต้นจะช่วยให้เรามีความเข้าใจในการเขียนโปรแกรม Java ลึกซึ้งยิ่งขึ้น