1 คะแนน โดย GN⁺ 2026-01-11 | 1 ความคิดเห็น | แชร์ทาง WhatsApp
  • พบ อาการหน่วยความจำรั่วร้ายแรง ใน เทอร์มินัลอีมูเลเตอร์ Ghostty ที่เมื่อรันเป็นเวลานานอาจใช้หน่วยความจำหลายสิบ GB
  • สาเหตุของปัญหาคือมีหน่วยความจำที่ไม่ถูกปลดปล่อยสะสมอยู่ เพราะไม่มีการเรียก munmap ใน ตรรกะการนำหน้าหน่วยความจำแบบไม่มาตรฐานกลับมาใช้ใหม่ ของโครงสร้าง PageList
  • เนื่องจาก Claude Code CLI สร้างเอาต์พุตกราฟหลายโค้ดพอยต์บ่อยครั้ง ทำให้มีการใช้หน้าหน่วยความจำแบบไม่มาตรฐานมากขึ้น และทำให้การรั่วไหลปรากฏในวงกว้าง
  • การแก้ไขได้เปลี่ยนเป็น ไม่ใช้หน้าหน่วยความจำแบบไม่มาตรฐานซ้ำ และปลดปล่อยทันที พร้อมใช้ ฟีเจอร์ VM tag ของ macOS เพื่อติดตามและยืนยันการรั่วไหล
  • การแก้ไขนี้ถูกประเมินว่าเป็นการแก้ปัญหาการรั่วไหลครั้งใหญ่ที่สุดของ Ghostty และมีกำหนดรวมอยู่ในรีลีสถัดไป (1.3)

ภาพรวมการรั่วไหลของหน่วยความจำใน Ghostty

  • ผู้ใช้บางรายรายงานว่า Ghostty ใช้หน่วยความจำ มากกว่า 37GB หลังจากเปิดใช้งานเป็นเวลานาน
    • การรั่วไหลนี้มีอยู่มาตั้งแต่ เวอร์ชัน 1.0 เป็นอย่างน้อย และช่วงหลังมานี้แอป CLI บางตัวตรงตามเงื่อนไขที่ทำให้ปัญหาถูกเปิดเผย
  • การแก้ไขได้ ถูกรวมเข้า GitHub แล้ว และมีกำหนดรวมอยู่ใน nightly build และรีลีสทางการ 1.3

โครงสร้าง PageList และวิธีจัดการหน่วยความจำ

  • Ghostty ใช้โครงสร้าง ลิงก์ลิสต์แบบเชื่อมสองทาง ชื่อ PageList เพื่อเก็บเนื้อหาในเทอร์มินัล
    • แต่ละหน้าจะมีข้อมูลอย่างอักขระ สไตล์ และไฮเปอร์ลิงก์
  • หน้าต่าง ๆ ถูกจัดสรรด้วย mmap และนำกลับมาใช้ใหม่ผ่าน พูลของหน้าขนาดมาตรฐาน
    • หน้าที่มีขนาดไม่เกินมาตรฐานจะถูกส่งกลับเข้าพูล
    • หน้าขนาดไม่มาตรฐาน ต้องถูกปลดปล่อยโดยตรงด้วย munmap
  • ตัวโครงสร้างนี้เองทำงานได้ตามปกติ แต่เกิดการรั่วไหลจาก บั๊กในตรรกะการปรับแต่งประสิทธิภาพ

การปรับแต่ง scrollback และสาเหตุที่เกิดบั๊ก

  • เมื่อ Ghostty เกิน scrollback-limit จะมีการปรับแต่งโดย นำหน้าที่เก่าที่สุดกลับมาใช้ใหม่
    • ทำให้เพิ่มประสิทธิภาพได้ด้วยการปรับเพียง pointer โดยไม่ต้องจัดสรรหน้าใหม่
  • ปัญหาคือในกระบวนการนี้มีการ เปลี่ยนเฉพาะ metadata ของหน้าที่ไม่มาตรฐานให้เป็นขนาดมาตรฐาน แต่ปล่อยให้หน่วยความจำจริงคงเดิม
    • เมื่อถึงเวลาปลดปล่อยในภายหลัง จึงถูกเข้าใจผิดว่าเป็นหน้ามาตรฐานและ ไม่มีการเรียก munmap
  • ส่งผลให้ หน้าที่ไม่มาตรฐานไม่ถูกปลดปล่อยและสะสมเพิ่มขึ้น จนกลายเป็นการรั่วไหลของหน่วยความจำขนาดใหญ่เมื่อรันระยะยาว

Claude Code กับการเปิดเผยการรั่วไหลในวงกว้าง

  • Claude Code CLI สร้างเอาต์พุตกราฟหลายโค้ดพอยต์บ่อยครั้ง ทำให้ ความถี่ในการใช้หน้าที่ไม่มาตรฐานเพิ่มขึ้น
    • อีกทั้งยังมีเอาต์พุต scrollback จำนวนมาก ทำให้การรั่วไหลสะสมได้รวดเร็ว
  • ตามการออกแบบของ Ghostty หน้าที่ไม่มาตรฐานควรเกิดขึ้นไม่บ่อย แต่ด้วยลักษณะการทำงานของ Claude Code ทำให้ สามารถทำซ้ำการรั่วไหลจำนวนมากได้
  • ผู้พัฒนาย้ำว่าบั๊กนี้ไม่ใช่ปัญหาของ Claude Code แต่เป็น ข้อบกพร่องในตรรกะภายในของ Ghostty

รายละเอียดการแก้ไข

  • วิธีแก้คือ ไม่ใช้หน้าที่ไม่มาตรฐานซ้ำ และปลดปล่อยทันทีด้วย munmap
    • หากพบหน้าที่ไม่มาตรฐานระหว่างกระบวนการ scrollback ก็จะจัดสรรมาตรฐานหน้าใหม่จากพูลแทน
  • แม้ผู้ใช้บางรายจะเสนอ กลยุทธ์การนำหน้าที่ไม่มาตรฐานกลับมาใช้ใหม่ แต่ในตอนนี้เลือกใช้การแก้แบบเรียบง่ายและปลอดภัยก่อน
  • ตัวอย่างโค้ดที่แก้ไข:
    if (first.data.memory.len > std_size) {
        self.destroyNode(first);
        break :prune;
    }
    

การติดตามการรั่วไหลด้วย VM tag

  • ใช้ ฟีเจอร์ VM tag ของ Mach kernel บน macOS เพื่อ กำหนดแท็กเฉพาะให้กับการจัดสรรหน่วยความจำของ PageList
    • ระหว่างการดีบักจึงสามารถระบุพื้นที่หน่วยความจำของ Ghostty ได้อย่างชัดเจน
    • ช่วยอย่างมากในการติดตามสาเหตุของการรั่วไหลและยืนยันผลการแก้ไข
  • ด้วยฟีเจอร์นี้จึงสามารถ ตรวจสอบด้วยสายตาได้ว่าหน่วยความจำที่เกี่ยวข้องกับ PageList ถูกปลดปล่อยหรือไม่

ระบบป้องกันการรั่วไหลของหน่วยความจำใน Ghostty

  • Ghostty มีระบบตรวจจับและป้องกันการรั่วไหลหลายรูปแบบ
    • ใช้ ตัวจัดสรรหน่วยความจำสำหรับตรวจจับการรั่วไหลของ Zig ในดีบักบิลด์และยูนิตเทสต์
    • รันการทดสอบทั้งหมดใน CI ด้วย valgrind
    • ตรวจสอบการรั่วไหลของ โค้ด Swift ด้วย macOS Instruments
    • PR ที่เกี่ยวข้องกับ GTK จะถูกตรวจสอบด้วย การทดสอบ GUI ผ่าน Valgrind
  • การรั่วไหลครั้งนี้เกิดขึ้น เฉพาะในเงื่อนไขบางแบบ จึงไม่สามารถทำซ้ำได้ด้วยการทดสอบเดิม
    • มีการเพิ่มเคสทดสอบใหม่เพื่อ ป้องกันการเกิดซ้ำของบั๊ก

บทสรุป

  • ปัญหานี้ได้รับการยืนยันว่าเป็นกรณี หน่วยความจำรั่วขนาดใหญ่ที่สุด ที่พบใน Ghostty
  • หลังการแก้ไขจะยังคงมีการติดตามอย่างต่อเนื่องผ่าน รายงานจากผู้ใช้และการทดสอบที่ทำซ้ำได้
  • ข้อมูลเพื่อการวินิจฉัยและกรณีที่ทำซ้ำได้ จากชุมชนมีบทบาทสำคัญอย่างยิ่งในการแก้ปัญหา
  • ย้ำว่าการมีสภาพแวดล้อมที่สามารถทำซ้ำปัญหาได้คือ หัวใจสำคัญของการแก้หน่วยความจำรั่ว

1 ความคิดเห็น

 
GN⁺ 2026-01-11
ความเห็นจาก Hacker News
  • เป็นข่าวที่น่ายินดีมาก ขอปรบมือให้ทุกคนที่มีส่วนร่วมในการแก้ปัญหานี้
    บั๊กนี้ถูกพูดถึงไปแล้วในเธรดนี้เมื่อสัปดาห์ก่อน
    ดูเหมือนว่า Claude Code จะเป็นตัวกระตุ้นให้บั๊กนี้ไปกระทบผู้ใช้มากขึ้น แต่ก็มีคนอย่างผมที่ไม่ได้ใช้ Claude Code เลยและยังเจอปัญหาเดียวกัน
    เกณฑ์ที่ทำให้หน้าถูกจัดว่าเป็น ‘ไม่มาตรฐาน (non-standard)’ นั้น ไม่ได้เป็นแบบขาวดำชัดเจน อย่างที่คิด
    และผมคิดว่าปัญหารั่วอาจเกิดบ่อยขึ้นกับคนที่ใช้การตั้งค่าอย่าง scrollback-limit = 0
    วิธีที่แก้ตอนนี้ก็อาจทำให้มีการลบแล้วสร้างหน้าที่ไม่มาตรฐานใหม่โดยไม่จำเป็น เลยแอบเสียดายว่าน่าจะรีไซเคิลหน้าเก่าที่เป็น non-standard อยู่แล้วได้หรือเปล่า

    • ส่วนนั้นในบล็อกโพสต์พูดถึงไว้แล้ว
      วิธีทำงานของ PageList ก็เหมือนเดิมมาตลอด และตอนมีบั๊กก็แค่ไปเห็นขนาดที่ผิดระหว่างการปรับความจุเท่านั้น
      ไม่น่าจะมีการเปลี่ยนแปลงด้านประสิทธิภาพที่รู้สึกได้
      ทางเลือกที่คุณเสนอมาก็เคยพิจารณาแล้ว แต่แนวทางปัจจุบันมี ข้อมูล benchmark รองรับเพียงพอ
      ผมเองก็พร้อมจะเปลี่ยนความเห็นได้ แต่ครั้งนี้โฟกัสที่การแก้ memory leak มากกว่าการเปลี่ยนโลกทัศน์ทั้งชุด
    • ถือว่าโชคดีที่เจอและรายงานปัญหานี้ได้ตั้งแต่ช่วงเบต้า
      มันเป็นบั๊กที่ทำให้เกิด segfault ได้จริงและรีโปรดิวซ์ได้
    • อนึ่ง ต้องยกเครดิตให้ Claude Code ที่ทำให้ CLI กลับมาดูน่าสนใจอีกครั้ง
      ในรอบ 20 ปีที่ผ่านมา ไม่มีอะไรทำให้ CLI ดูสดใหม่ได้เท่านี้เลย
    • เธรดเรื่อง memory leak อยู่ที่นี่
  • เป็นบทความที่ยอดเยี่ยมมาก ขอบคุณ mitchellh ที่สร้าง Ghostty ขึ้นมา
    ผมย้ายมาใช้ตั้งแต่ปีที่แล้วและไม่เคยเสียใจเลย
    แต่ก็แปลกใจนิดหน่อยที่แพตช์นี้จะถูกรวมอยู่ในฟีเจอร์รีลีสอีกหลายเดือนข้างหน้า
    นึกว่าจะเข้า bugfix release

    • มันถูกรวมอยู่ใน nightly build ล่าสุดแล้ว
  • พอเริ่มพูดถึง page ผมก็คิดทันทีว่า “อ๋อ เป็น memory pooling” แล้วต่อด้วย “น่าจะเป็น ring buffer” และก็ใช่จริง ๆ คือการ นำ scrollback กลับมาใช้ซ้ำ
    ผมเดาตำแหน่งบั๊กได้เลยเหมือนกัน — เป็นส่วนที่ไม่ได้ free หน่วยความจำของ page อย่างถูกต้อง
    ไดอะแกรมการจัดแนวหน่วยความจำก็ทำได้ดีมาก
    มันย้ำเตือนอีกครั้งว่าทุกครั้งที่ลองทำอะไรใหม่ ๆ ก็มี โอกาสเกิด leak ได้เสมอ

  • ผมเพิ่งย้ายมา Ghostty ในสัปดาห์นี้ และระหว่างพัฒนาแอป terminal UI ก็เจอ OOM crash
    โครงสร้างของมันใช้ไอคอน UTF8 ใน tab bar และพอ resize terminal ก็ crash ทันที
    รีโปรดิวซ์ได้ง่ายมากจนกำลังจะเตรียม bug report อยู่แล้ว แต่ดูเหมือนจะคล้ายกับปัญหาที่อธิบายในบล็อกโพสต์มาก
    หวังว่าจะได้รับการแก้ไข

  • ผมถาม @mitchellh ว่าใช้เครื่องมืออะไรทำ visualization หน่วยความจำ และเว็บก็ทำงานบนมือถือได้ดีมาก เลยอยากรู้ว่า stack ที่ใช้คืออะไร

    • ใช้ static HTML/CSS ที่สร้างด้วย Opus 4.5
      โค้ดสำหรับ visualization เป็นงานใช้ครั้งเดียว เลยตรวจแค่ ความถูกต้อง มากกว่าคุณภาพ
      แยก namespace ตามแต่ละบล็อกโพสต์และไม่ได้เอากลับมาใช้ซ้ำ
      แค่ตรวจว่ามันไม่ได้ทำอะไรแปลก ๆ (เช่น ขุดบิตคอยน์หรือข้อมูลลับรั่วไหล)
      ประเด็นสำคัญคือการสื่อสารข้อมูล และไดอะแกรมแบบนี้ช่วยให้เนื้อหา เข้าใจง่ายขึ้นมาก
  • ผมยังติดตามการพัฒนา Ghostty อยู่เรื่อย ๆ
    มันให้ความรู้สึก overengineering อยู่นิดหน่อย แต่บั๊กโพสต์มอร์เท็มแบบนี้มีคุณค่ามากสำหรับคนที่รักงานช่างฝีมือ

    • อยากรู้ว่าในมุมไหนที่คุณรู้สึกว่ามัน overengineering
  • ถ้าเป็น terminal ที่เขียนด้วย Rust จะจัดการ implementation แบบนี้อย่างไรโดยไม่เสีย performance ก็น่าสนใจเหมือนกัน

  • ถึงจะไม่ค่อยรู้เรื่อง Ghostty หรือ terminal emulator มากนัก ก็ยังอ่านแล้วเข้าใจได้ง่าย
    ประทับใจกับการอธิบายที่เข้าถึงง่ายและเป็นมิตร

  • ย้ำให้เห็นอีกครั้งว่าการมี bug report ที่รีโปรดิวซ์ได้ สำคัญแค่ไหน

  • กำลังรอว่าจะมีใครพูดว่า “ถ้าใช้ Rust เรื่องนี้คงไม่เกิดขึ้น” ไหม

    • คงต้องรอนานหน่อย
      Rust ไม่ได้รับประกัน ‘leak safety’ ในระดับภาษา
      แม้แต่ safe Rust ก็ทำให้หน่วยความจำรั่วได้ — เพียงแต่นี่ไม่ใช่ปัญหาด้าน safety
      แม้แต่ใน standard API ก็ยังมีการอนุญาตให้ leak อย่างชัดเจน เช่น Box::leak
      Rust แค่ทำให้การสร้าง leak ที่ไม่ได้ตั้งใจ เกิดขึ้นได้ยากขึ้น ไม่ได้ป้องกันได้อย่างสมบูรณ์