Scala for Backend Engineering & Functional Programming · บทเรียน

การจัดการหน่วยความจำและการปรับแต่ง GC

เจาะลึกการจัดการหน่วยความจำของ JVM การเก็บคืนหน่วยความจำ และเทคนิคเพิ่มประสิทธิภาพการใช้หน่วยความจำใน Scala

บทเรียน 2 จาก 311 ขั้นตอน

การจัดการหน่วยความจำและการปรับแต่ง GC เป็นบทเรียน Scala for Backend Engineering & Functional Programming ฟรีบน CoddyKit นี่คือบทเรียนที่ 2 จากทั้งหมด 3 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Scala for Backend Engineering & Functional Programming และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Scala for Backend Engineering & Functional Programming มีบทเรียนทั้งหมด 3 บทเรียน

บทนำหน่วยความจำ JVM และการเก็บขยะ

ยินดีต้อนรับ ในบทเรียนนี้ เราจะเจาะลึกวิธีที่ Java Virtual Machine (JVM) จัดการหน่วยความจำ โดยเน้นประเด็นที่สำคัญต่อแอปพลิเคชัน Scala

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

ฮีป: พื้นที่จัดเก็บออบเจ็กต์

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

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

สแต็กกับฮีป: ความแตกต่างที่สำคัญ

ฮีปใช้เก็บออบเจ็กต์ ส่วนสแต็กใช้เก็บตัวแปรเฉพาะที่ (โดยเฉพาะชนิดข้อมูลพื้นฐานและการอ้างอิงออบเจ็กต์) รวมถึงเฟรมการเรียกเมธอด แต่ละเธรดมีสแต็กเป็นของตัวเอง

  • ฮีป: ใช้เก็บออบเจ็กต์ ใช้ร่วมกัน และจัดการโดยการเก็บขยะ
  • สแต็ก: ใช้เก็บการเรียกเมธอดและตัวแปรเฉพาะที่ แยกตามเธรด และจัดการโดยอัตโนมัติเมื่อเมธอดเริ่มทำงานหรือสิ้นสุดการทำงาน

การเข้าใจความแตกต่างนี้เป็นกุญแจสำคัญในการแก้ไขปัญหาหน่วยความจำ

พื้นฐานการเก็บขยะ

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

แทนที่จะต้องคืนหน่วยความจำด้วยตนเองเหมือนใน C++ ภาษา Scala (และ Java) อาศัยการเก็บขยะเพื่อป้องกันหน่วยความจำรั่วและทำให้การพัฒนาง่ายขึ้น แนวคิดหลักคือ “ทำเครื่องหมายและกวาดล้าง” โดยทำเครื่องหมายออบเจ็กต์ที่เข้าถึงได้ แล้วกวาดออบเจ็กต์ที่เหลือออก

อธิบายการเก็บขยะแบบแบ่งรุ่น

ระบบเก็บขยะสมัยใหม่ส่วนใหญ่ใช้แนวทางแบบแบ่งรุ่น โดยแบ่งฮีปออกเป็นพื้นที่ตามอายุของออบเจ็กต์:

  • รุ่นใหม่: พื้นที่สำหรับจัดสรรออบเจ็กต์ใหม่ ออบเจ็กต์ส่วนใหญ่จะหมดอายุอยู่ที่นี่
  • รุ่นเก่า: ออบเจ็กต์ที่อยู่รอดจากการเก็บขยะในรุ่นใหม่หลายครั้งจะถูกเลื่อนมาอยู่ที่นี่

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

คอลเลกชัน Scala และหน่วยความจำ

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

ระบบเก็บขยะได้รับการปรับให้เหมาะกับกรณีนี้ มาดูตัวอย่างการสร้างออบเจ็กต์ชั่วคราวระหว่างประมวลผลรายการกัน:

object Main {
  def main(args: Array[String]): Unit = {
    println("Creating and transforming a list...")
    val originalList = (1 to 100000).toList // ~100k objects
    val transformedList = originalList.map(x => x * 2).filter(_ % 3 == 0)
    println(s"Transformed list size: ${transformedList.size}")
    // originalList and intermediate lists from map are now eligible for GC
    println("Intermediate objects are efficiently managed by GC.")
  }
}

สถานการณ์หน่วยความจำรั่วที่พบบ่อย

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

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

การอ้างอิงแบบอ่อนสำหรับแคช

สำหรับแคชที่คุณต้องการให้การเก็บขยะเรียกคืนหน่วยความจำได้ หากออบเจ็กต์ถูกอ้างอิงโดยแคชเพียงอย่างเดียว ให้ใช้ java.lang.ref.WeakReference

WeakReference จะไม่ป้องกันไม่ให้สิ่งที่อ้างอิงถูกเก็บขยะ หากการอ้างอิงที่เหลืออยู่ต่อออบเจ็กต์มีเพียงการอ้างอิงแบบอ่อน ออบเจ็กต์นั้นจะมีสิทธิ์ถูกเก็บขยะ

import java.lang.ref.WeakReference

object Main {
  def main(args: Array[String]): Unit = {
    var largeData: Array[Byte] = new Array[Byte](1024 * 1024) // 1MB
    val weakCacheEntry = new WeakReference(largeData)

    println(s"Data exists via weak ref: ${weakCacheEntry.get() != null}")

    largeData = null // Remove the strong reference

    System.gc() // Hint to the JVM to run GC
    Thread.sleep(100) // Give GC time to run

    println(s"Data collected (possibly): ${weakCacheEntry.get() == null}")
    println("WeakReference allows GC to clean up if no strong references remain.")
  }
}

แฟล็ก JVM พื้นฐานสำหรับปรับแต่งการเก็บขยะ

แม้การเก็บขยะจะทำงานโดยอัตโนมัติ แต่คุณสามารถปรับพฤติกรรมของมันได้โดยใช้อาร์กิวเมนต์ JVM แฟล็กสำคัญมีดังนี้:

  • -Xmx: กำหนดขนาดสูงสุดของฮีป Java เช่น -Xmx4g สำหรับ 4 กิกะไบต์
  • -Xms: กำหนดขนาดฮีป Java เริ่มต้น เช่น -Xms512m สำหรับ 512 เมกะไบต์
  • -XX:+UseG1GC: ระบุตัวเก็บขยะ Garbage-First (G1) ซึ่งเป็นตัวเลือกสมัยใหม่ที่ใช้กันทั่วไป

การปรับแต่งแฟล็กเหล่านี้อาจส่งผลอย่างมากต่อประสิทธิภาพของแอปพลิเคชันและการใช้หน่วยความจำ

ตรวจสอบความเข้าใจของคุณ

ข้อความใดต่อไปนี้เกี่ยวกับการจัดการหน่วยความจำของ JVM และการเก็บขยะเป็น TRUE

ทบทวน: หน่วยความจำและการเก็บขยะ

ทำได้ดีมาก คุณได้สำรวจพื้นฐานของการจัดการหน่วยความจำใน JVM และการเก็บขยะแล้ว:

  • ฮีป ใช้เก็บออบเจ็กต์ ส่วนสแต็กใช้เก็บการเรียกเมธอดและตัวแปรเฉพาะที่
  • การเก็บขยะ เรียกคืนหน่วยความจำจากออบเจ็กต์ที่เข้าถึงไม่ได้โดยอัตโนมัติ
  • การทำความเข้าใจการเก็บขยะแบบแบ่งรุ่น (รุ่นใหม่/รุ่นเก่า) ช่วยเพิ่มประสิทธิภาพได้
  • ควรระวังหน่วยความจำรั่ว และใช้เครื่องมืออย่าง WeakReference สำหรับความต้องการด้านแคชเฉพาะกรณี
  • แฟล็ก JVM พื้นฐานอย่าง -Xmx และ -Xms ใช้ควบคุมขนาดฮีป

ถัดไป เราจะเจาะลึกเครื่องมือวิเคราะห์ประสิทธิภาพเพื่อระบุคอขวด

เริ่มต้นได้ฟรี

เรียนรู้ Scala ด้วย AI tutor — ฟรี

เขียนและเรียกใช้โค้ดจริงในเบราว์เซอร์ของคุณ รับความช่วยเหลือทันทีจาก AI tutor 24/7 และเรียนรู้ต่อจากที่คุณหยุดบนเว็บหรือในแอป

คอร์ส
39
บทเรียน
143

คำถามที่พบบ่อย

บทเรียน “การจัดการหน่วยความจำและการปรับแต่ง GC” ฟรีหรือไม่

ใช่ — ข้อความเต็มของ “การจัดการหน่วยความจำและการปรับแต่ง GC” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Scala for Backend Engineering & Functional Programming ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Scala for Backend Engineering & Functional Programming มีบทเรียนทั้งหมด 3 บทเรียน

คุณจะเรียนรู้อะไรในบทเรียน “การจัดการหน่วยความจำและการปรับแต่ง GC”

เจาะลึกการจัดการหน่วยความจำของ JVM การเก็บคืนหน่วยความจำ และเทคนิคเพิ่มประสิทธิภาพการใช้หน่วยความจำใน Scala คุณปฏิบัติ Scala for Backend Engineering & Functional Programming ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน

คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Scala for Backend Engineering & Functional Programming หรือไม่

ไม่จำเป็นต้องมีประสบการณ์มาก่อน Scala for Backend Engineering & Functional Programming บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 2 จากทั้งหมด 3 บทเรียน

บทเรียน “การจัดการหน่วยความจำและการปรับแต่ง GC” ใช้เวลานานแค่ไหน

บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย

ฉันเขียนและรันโค้ดในบทเรียน Scala for Backend Engineering & Functional Programming นี้ได้ไหม

ได้ บทเรียน Scala for Backend Engineering & Functional Programming ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. การวิเคราะห์ประสิทธิภาพแอปพลิเคชัน Scala
  2. การจัดการหน่วยความจำและการปรับแต่ง GC
  3. การเพิ่มประสิทธิภาพโค้ดพร้อมกัน
← กลับไปที่ Scala for Backend Engineering & Functional Programming