0Pricing
Java Academy · บทเรียน

การตรวจจับและแก้ไขหน่วยความจำรั่ว

ระบุรูปแบบหน่วยความจำรั่วที่พบบ่อย เช่น คอลเลกชันแบบ static ตัวรับฟัง และแคช พร้อมแก้ไขปัญหา

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

หน่วยความจำรั่วใน Java คืออะไร

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

การสะสมคอลเลกชันแบบคงที่

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

public class Cache {
    // LEAK: static list grows forever if items are never removed
    private static final List<Object> items = new ArrayList<>();
    public static void add(Object o) { items.add(o); }
    // Fix: add a remove() method or use a bounded cache
}

ตัวฟังเหตุการณ์ที่ไม่ได้ยกเลิกการลงทะเบียน

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

// Leak:
sensor.addListener(new DataLogger());
// Fix:
DataLogger logger = new DataLogger();
sensor.addListener(logger);
// ... when done:
sensor.removeListener(logger);

ตัวแปร ThreadLocal ที่ไม่ได้ล้างค่า

ในพูลเธรด ค่า ThreadLocal จะคงอยู่ระหว่างงานต่าง ๆ เพราะมีการนำเธรดกลับมาใช้ซ้ำ หากไม่ล้างค่า ข้อมูลของงานหนึ่งจะรั่วไหลไปยังงานถัดไปที่ทำงานบนเธรดเดียวกัน

private static final ThreadLocal<MyContext> CTX = new ThreadLocal<>();
// Always clean up after each task:
try {
    CTX.set(new MyContext(requestId));
    doWork();
} finally {
    CTX.remove(); // prevents leak in pooled threads
}

การรั่วไหลของตัวโหลดคลาสในแอปที่ปรับใช้ใหม่ขณะทำงาน

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

การตรวจหารอยรั่วด้วยฮีปดัมป์

สร้างฮีปดัมป์ด้วย jmap -dump:format=b,file=heap.hprof <pid> จากนั้นเปิดใน Eclipse MAT หรือ VisualVM เพื่อค้นหาออบเจ็กต์ที่ยึดหน่วยความจำไว้มากที่สุดและรากของการเก็บขยะ

// Take a heap dump:
jmap -dump:live,format=b,file=heap.hprof $(jps | grep MyApp | cut -d" " -f1)
// Or trigger on OOM:
// -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp/heap.hprof

เครื่องมือวิเคราะห์หน่วยความจำ Eclipse (MAT)

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

การใช้ WeakReference เพื่อป้องกันการรั่วไหล

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

Map<String, WeakReference<Image>> imageCache = new HashMap<>();
imageCache.put("logo", new WeakReference<>(loadImage("logo.png")));
Image logo = imageCache.get("logo") != null ? imageCache.get("logo").get() : null;
if (logo == null) logo = reload("logo.png"); // re-load if GCed

แคชจำกัดขนาดด้วย LinkedHashMap LRU

เขียนทับ removeEldestEntry ใน LinkedHashMap เพื่อจำกัดขนาดแคชและนำรายการที่ไม่ได้ใช้งานนานที่สุดออกโดยอัตโนมัติ

Map<String, String> lruCache = new LinkedHashMap<>(16, 0.75f, true) {
    protected boolean removeEldestEntry(Map.Entry<String, String> e) {
        return size() > 100; // evict when over 100 entries
    }
};

การทำโปรไฟล์การจัดสรรหน่วยความจำด้วย Java Flight Recorder

JFR (เครื่องมือบันทึกการทำงานของ Java) บันทึกโปรไฟล์การจัดสรรหน่วยความจำโดยมีค่าใช้จ่ายเพิ่มเติมน้อยมาก ให้เปิดใช้งานด้วย -XX:StartFlightRecording และวิเคราะห์ด้วยเครื่องมือควบคุมการทำงานของ JDK

// Start a 60-second JFR recording:
java -XX:StartFlightRecording=duration=60s,filename=rec.jfr MyApp
// Or via jcmd:
jcmd <pid> JFR.start duration=60s filename=rec.jfr

รายการตรวจสอบการแก้ไขการรั่วไหล

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

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

แฟล็ก JVM ใดจะสร้างฮีปดัมป์โดยอัตโนมัติเมื่อเกิด OutOfMemoryError

สรุปทบทวน

แหล่งที่มาทั่วไปของการรั่วไหลใน Java ได้แก่ คอลเลกชันแบบ static ตัวรับฟังที่ไม่ได้ยกเลิกการลงทะเบียน ThreadLocals ในพูล และแคชที่ไม่มีขอบเขต ตรวจจับด้วยฮีปดัมป์ร่วมกับ MAT แก้ไขด้วย WeakReferences โครงสร้างที่จำกัดขนาด และลบการอ้างอิงออกทุกครั้งเมื่อใช้งานเสร็จ

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

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

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

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

ระบุรูปแบบหน่วยความจำรั่วที่พบบ่อย เช่น คอลเลกชันแบบ static ตัวรับฟัง และแคช พร้อมแก้ไขปัญหา คุณปฏิบัติ Java Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน

คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Java Academy หรือไม่

ไม่จำเป็นต้องมีประสบการณ์มาก่อน Java Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน

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

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

ฉันเขียนและรันโค้ดในบทเรียน Java Academy นี้ได้ไหม

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

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

  1. ภูมิภาคฮีปของ JVM และวงจรชีวิตออบเจ็กต์
  2. อัลกอริทึม GC: Serial, G1, ZGC, Shenandoah
  3. การตรวจจับและแก้ไขหน่วยความจำรั่ว
  4. แฟล็กปรับแต่ง GC และการทำโปรไฟล์ด้วย JVisualVM
← กลับไปที่ Java Academy