"การใช้หน่วยความจำ" ของ Windows หมายถึงอะไรจริง ๆ? — อ่าน Working Set, Private Bytes, Commit และเพจไฟล์ให้ถูก

· · Windows, การพัฒนา Windows, การจัดการหน่วยความจำ, Working Set, Private Bytes, Commit, เพจไฟล์, การเฝ้าดูประสิทธิภาพ, การแก้ปัญหา, Sysinternals

Task Manager แสดง “Memory” ของโปรเซสเป็น 1.2GB แต่ Process Explorer แสดง Working Set 1.5GB และ Private Bytes 2.4GB และ Size ของ VMMap ใหญ่กว่าอีก เมื่อดูระบบทั้งก้อนจะอ่านว่า “Committed 19.6/31.8GB”

แล้วท้ายที่สุดแอปนี้ใช้หน่วยความจำกี่กิกะไบต์จริง ๆ

คำตอบคือ ตัวเลขที่ควรดูขึ้นกับสิ่งที่คุณอยากรู้จริง ๆ เมตริกต่างกันตามว่าคุณอยากรู้ปริมาณที่อยู่ใน RAM ตอนนี้ ปริมาณที่จัดสรรเฉพาะโปรเซสนั้น ปริมาณที่ระบบสัญญาจะรองรับต่อไป หรือเพียงช่วงที่อยู่เสมือนที่จองไว้

สิ่งที่ทำให้เมตริกหน่วยความจำ Windows สับสนคือทั้งหมดแสดงภายใต้คำเดียวว่า “หน่วยความจำ” ทั้งที่จริงแล้ววัดแกนที่แยกกันดังนี้

  • ใช้ พื้นที่ที่อยู่ เท่าใด
  • บริโภค commit เท่าใด
  • อยู่ใน RAM กายภาพ ตอนนี้หรือไม่
  • เพจนั้น เป็นของโปรเซสเอง หรือใช้ร่วมได้
  • ระบบทั้งก้อนยังรองรับการจัดสรรได้อีกเท่าใด

บทความนี้สำหรับผู้ที่สอบสวนหน่วยความจำแอปที่โต หรือการขาดหน่วยความจำทั้งระบบบน Windows 10/11 และ Windows Server ปัจจุบัน และเชื่อมความสัมพันธ์ของ Working Set, Private Working Set, Private Bytes, Commit, Virtual Bytes, เพจไฟล์, Available และเพจฟอลต์ในภาพเดียว

ขั้นตอนไล่เหตุที่อ็อบเจกต์ .NET ไม่ถูกเก็บมีรายละเอียดใน “แยกความหน่วง GC ออกจากการรั่วหน่วยความจำใน .NET” และการใช้งานจริงของ VMMap กับ Process Explorer อยู่ใน “Process Explorer / Handle / VMMap ในทางปฏิบัติ” บทความนี้โฟกัสที่ข้อกำหนดเบื้องต้นของทั้งคู่: วิธีอ่านตัวเลขฝั่ง OS ของ Windows

1. สรุปก่อนเลย

  • Working Set คือชุดเพจที่อยู่ใน RAM ตอนนี้ รวมไม่เฉพาะเพจของโปรเซสเอง แต่รวมเพจที่ใช้ร่วมกับโปรเซสอื่นได้ เช่นโค้ด DLL และไฟล์แมปหน่วยความจำ1
  • Private Working Set คือส่วนของ Working Set ที่เป็นของโปรเซสนั้นเท่านั้นตอนนี้ ใช้เป็นค่าประมาณ “RAM ที่โปรเซสนี้ครองอยู่คนเดียวตอนนี้” ได้ แต่ไม่ใช่ปริมาณทั้งหมดที่แอปจัดสรร2
  • Private Bytes คือปริมาณ commit ที่เป็นของโปรเซสนั้น เป็นเมตริกแยกจากว่าหน่วยความจำอยู่ใน RAM ตอนนี้หรือไม่ ฟิลด์ PagefileUsage ในโครงสร้าง Win32 API บน Windows ปัจจุบันก็แทน Commit Charge เดียวกันโดยพฤตินัย ไม่ใช่จำนวนไบต์ที่เขียนลงเพจไฟล์จริง2
  • “Committed X/Y” ของ Task Manager แสดง X เป็น commit รวมปัจจุบันของระบบ และ Y เป็นเพดาน commit X ไม่ใช่การใช้เพจไฟล์ Y ประมาณจาก RAM บวกเพจไฟล์3
  • Reserve กับ Commit เป็นคนละเรื่อง เพียงจองช่วงที่อยู่เสมือนคือกันช่วงนั้นไว้ใช้ภายหลัง ไม่กิน RAM หรือเพดาน commit ในปริมาณเดียวกัน45
  • เพจฟอลต์ไม่จำเป็นต้องหมายถึง I/O ดิสก์ มีซอฟต์ฟอลต์ที่แก้ใน RAM ได้ และฮาร์ดฟอลต์ที่อ่านจากเพจไฟล์ ไฟล์ปฏิบัติการ ไฟล์แมปหน่วยความจำ เป็นต้น16
  • การรั่วหน่วยความจำตัดสินจากแนวโน้มเมื่อทำโหลดเดิมซ้ำ ไม่ใช่จากค่าครั้งเดียว โดยเฉพาะดูว่า Private Bytes และรายละเอียดยังไต่ขึ้นทีละขั้นหลังประมวลผลจบ โดยไม่กลับสู่สถานะคงที่เดิม

ประโยคเดียว: Working Set คือ “ปริมาณที่อยู่ใน RAM ตอนนี้” Private Bytes คือ “ปริมาณที่สัญญาเฉพาะโปรเซสนี้” และ Commit คือ “ปริมาณที่ระบบทั้งก้อนสัญญา”

เลือกเมตริกหน่วยความจำ Windows ที่ถูกเมตริกที่ดูขึ้นกับว่าอยากรู้การอยู่ใน RAM commit ของโปรเซส commit ทั้งระบบ หรือช่วงที่อยู่เสมือนปริมาณที่อยู่ใน RAM ตอนนี้ปริมาณที่สัญญาเฉพาะโปรเซสปริมาณที่สัญญาระบบทั้งก้อนช่วงที่อยู่ที่จองไว้คุณอยากรู้อะไรเกี่ยวกับการใช้หน่วยความจำWorking SetPrivate BytesSystem CommitVirtual Bytes / Reservedการอยู่ใน RAM กายภาพCommit ของโปรเซสเทียบกับ Commit Limitพื้นที่ที่อยู่เสมือน

ภาพ 1: แยกการสังเกต “หน่วยความจำสูง” เป็นสี่คำถามก่อน

2. แยก “การใช้หน่วยความจำ” เป็นสี่แกน

เริ่มต้นคิดหน่วยความจำ Windows ไม่ใช่ “แท่งเดียว” แต่ตามสี่แกน

สี่แกนอิสระสำหรับจำแนกหนึ่งเพจตรวจสถานะที่อยู่เสมือน แบ็กกิงของเพจที่ commit การอยู่ใน RAM กายภาพ และความใช้ร่วมกับโปรเซสอื่นแยกกันดูหนึ่งเพจตามสี่แกนสถานะที่อยู่Free / Reserved / Committedแบ็กกิงPage-file-backed / File-backedการอยู่ใน RAMResident / Not residentความใช้ร่วมได้Private / Shareable

ภาพ 2: แม้เพจเดียว สถานะที่อยู่ แบ็กกิง การอยู่ และความใช้ร่วมก็กำหนดอิสระ

Mapped ไม่ใช่สถานะที่อยู่คู่กับ Free, Reserved และ Committed — เป็นหมวดของบริเวณ เพจในวิวที่แมปก็ Committed ได้ เช่นกัน Private ไม่ใช่สื่อแบ็กกิง แต่เป็นการจำแนกความใช้ร่วม ดังนั้นอ่านแบ็กกิงเป็น Page-file-backed หรือ File-backed และความใช้ร่วมเป็น Private หรือ Shareable แยกกัน

รวมสี่แกนนี้ได้ความสัมพันธ์ของเมตริกตัวแทนดังนี้

สถานะเพจ Working Set Private Working Set Private Bytes ตระกูล Virtual Bytes
ของโปรเซส commit อยู่ใน RAM รวม รวม รวม รวม
ของโปรเซส commit ไม่อยู่ใน RAM ไม่รวม ไม่รวม รวม รวม
เพจร่วมของ DLL หรือไฟล์แมป อยู่ใน RAM รวม โดยทั่วไปไม่รวม โดยทั่วไปไม่รวม รวม
จองแล้วแต่ยังไม่ commit ไม่รวม ไม่รวม ไม่รวม อาจรวม
ช่วงที่อยู่ที่ไม่ได้ใช้ ไม่รวม ไม่รวม ไม่รวม มักไม่รวม
การจับคู่ชนิดเพจกับเมตริกหน่วยความจำหลักแสดงว่าเมตริกใดรวมเพจส่วนตัวที่อยู่ใน RAM เพจส่วนตัวที่ไม่อยู่ เพจร่วมที่อยู่ใน RAM และช่วงที่จองอย่างเดียวส่วนตัว commit อยู่ใน RAMส่วนตัว commit ไม่อยู่ใน RAMเพจร่วม อยู่ใน RAMจองแล้ว ไม่ commitWorking SetPrivate Working SetPrivate Bytesตระกูล Virtual Bytes

ภาพ 3: Working Set กับ Private Bytes นับชุดเพจต่างกัน จึงไม่ใช่ความสัมพันธ์การบรรจุแบบง่าย

จุดสำคัญคือ Working Set กับ Private Bytes ไม่ได้อยู่ในความสัมพันธ์การบรรจุแบบง่าย

Private Bytes รวมเพจที่เป็นของโปรเซสแต่ไม่อยู่ใน RAM ตอนนี้ Working Set ในทางกลับกันรวมเพจร่วม เช่นโค้ด DLL และหน่วยความจำร่วม ที่ Private Bytes ไม่นับเลย ดังนั้นตามโปรเซสและช่วงเวลา Working Set อาจใหญ่กว่า Private Bytes หรือกลับกัน

และเพียงรวม Working Set ของหลายโปรเซสอาจนับเพจกายภาพเดียวกัน เช่น DLL ที่ใช้ร่วม มากกว่าหนึ่งครั้ง “ผลรวม Working Set ของแต่ละโปรเซสเท่ากับ RAM ที่ใช้” ไม่จำเป็นต้องเป็นจริง

3. พื้นที่ที่อยู่เสมือน — Reserve กับ Commit เป็นคนละเรื่อง

3.1. ที่อยู่เสมือนไม่ใช่ที่อยู่ RAM กายภาพ

แต่ละโปรเซสมีพื้นที่ที่อยู่เสมือนของตนเอง พอยน์เตอร์ที่แอปใช้ไม่ได้ชี้ตำแหน่งใน RAM กายภาพโดยตรง Windows ใช้ตารางเพจแมปกที่อยู่เสมือนไปยังเพจกายภาพหรือข้อมูลบนไฟล์7

ผลคือแม้ PC มี RAM 64GB พื้นที่ที่อยู่เสมือนที่โปรเซส 32 บิตใช้ได้มักเล็กกว่านั้นมาก ในทางกลับกันโปรเซส 64 บิตมีพื้นที่ที่อยู่เสมือนใหญ่กว่า RAM กายภาพก็เป็นเรื่องปกติ

3.2. Reserved หมายถึงแค่ “กันที่อยู่ไว้”

MEM_RESERVE ของ VirtualAlloc จองช่วงที่อยู่เสมือนต่อเนื่องเพื่อใช้ภายหลัง ในขั้นนี้ยังไม่มีที่เก็บกายภาพผูกกับเพจ และช่วงนั้นอ่านเขียนไม่ได้45

ตัวอย่างเช่นฐานข้อมูลหรือรันไทม์ Reserve ช่วงที่อยู่ 8GB เพื่อโตในอนาคต ก็ไม่กิน RAM 8GB หรือ Private Bytes 8GB เพียงแค่นั้น

3.3. Committed คือสัญญาว่า “จะรองรับเมื่อต้องการ”

MEM_COMMIT คือการทำให้เพจเสมือนอยู่ในสถานะ Committed และให้ Windows สัญญาว่าจะให้แบ็กกิงที่จำเป็น การอ่าน เขียน หรือรันได้รับอนุญาตจริงหรือไม่ตัดสินแยกด้วยการป้องกันเพจ — PAGE_READONLY, PAGE_READWRITE, PAGE_EXECUTE, PAGE_NOACCESS เป็นต้น — ดังนั้นการเป็น Committed เองไม่หมายถึง “อ่านเขียนได้” ขณะ commit จะนับเข้า Commit Charge ของระบบ แต่เพจกายภาพจริงอาจยังไม่ถูกมอบจนเข้าถึงครั้งแรก เพจที่แตะครั้งแรกถูกตั้งศูนย์ ผ่าน demand-zero fault แล้วเข้า Working Set51

ดังนั้นแม้เรียก “จัดสรร” ทั้งสองแบบ จริงมีสามขั้นต่อไปนี้

สามขั้นจาก Reserve ผ่าน Commit สู่การอยู่ใน RAMแสดงการจองที่อยู่เสมือน การ commit เพจ และการเข้าถึงครั้งแรกที่มอบเพจกายภาพแล้วเข้า Working SetMEM_COMMITเข้าถึงครั้งแรก demand-zero faultถ้าไม่เคยเข้าถึงMEM_RESERVE - จองช่วงที่อยู่สะท้อนในตระกูล Virtual BytesCommitted - เข้าถึงได้ตามการป้องกันเพจสะท้อนใน Private Bytes / System Commitมอบเพจกายภาพ อยู่ใน RAMสะท้อนใน Working Setcommit แล้วแต่ไม่อยู่

ภาพ 4: Reserve, Commit และการเข้าถึงครั้งแรกเป็นเหตุการณ์แยก และแต่ละอันขยับเมตริกคนละตัว

สามขั้นนี้ขยับตัวเลขของตระกูล Virtual Bytes, Private Bytes และ Working Set แยกกัน

3.4. ทำไมจึงเกิด OutOfMemory ได้แม้ยังมี RAM ว่าง

ความสำเร็จของการจัดสรรหน่วยความจำไม่ได้ตัดสินจาก RAM ว่างอย่างเดียว

  • โปรเซสหมดพื้นที่ที่อยู่เสมือน
  • ไม่มีช่วงที่อยู่ว่างขนาดที่ต้องการที่ต่อเนื่อง
  • Commit Charge ทั้งระบบถึง Commit Limit
  • Job Object คอนเทนเนอร์ รันไทม์ หรือไลบรารีมีขีดจำกัดของตนเอง
  • เป็นโปรเซส 32 บิต
  • ฮีปเนทีฟแตกเป็นชิ้น

แม้บน Windows 64 บิต พื้นที่ที่อยู่เสมือนโหมดผู้ใช้ของโปรเซส 32 บิตมักเป็น 2GB หากไม่ตั้ง IMAGE_FILE_LARGE_ADDRESS_AWARE แอป 32 บิตที่มีแฟล็กนั้นใช้ได้ถึง 4GB บน Windows 64 บิต8

ดังนั้น “PC มี RAM ว่าง 20GB แต่แอป 32 บิตล้มที่ราว 1.6GB” ไม่ใช่ข้อขัดแย้ง อาจไม่ใช่ปัญหา RAM เลย แต่เป็นการแตกของพื้นที่ที่อยู่หรือชนขีดจำกัดแข็ง

4. Working Set — เพจที่อยู่ใน RAM ตอนนี้

Working Set คือชุดเพจในพื้นที่ที่อยู่เสมือนของโปรเซสที่อยู่ใน RAM กายภาพตอนนี้1

ชุดนี้ผสมสิ่งต่อไปนี้

  • ฮีปและสแตกของโปรเซสเอง
  • โค้ดและข้อมูลอ่านอย่างเดียวของ EXE และ DLL
  • ไฟล์แมปหน่วยความจำ
  • หน่วยความจำร่วม
  • เพจที่กลายเป็นของโปรเซสนั้นหลัง copy-on-write
  • เพจที่รันไทม์และไลบรารีต่าง ๆ แตะ

4.1. Working Set ที่โตไม่จำเป็นต้องหมายถึงจัดสรรเพิ่ม

การเข้าถึงเพจที่ commit แล้วครั้งแรกอาจเพิ่มเฉพาะ Working Set ขณะ Private Bytes คงที่ เช่นกันเมื่อแมปไฟล์ใหญ่แล้วอ่านตามลำดับ เพจที่แบ็กด้วยไฟล์เข้า Working Set ขณะ Private Bytes แทบไม่เพิ่ม

ในทางกลับกันเมื่อ Windows Trim Working Set ตามแรงดันหน่วยความจำ Working Set อย่างเดียวหด ขณะแอปยังถือหน่วยความจำเดิมตามตรรกะ การแตะอีกครั้งภายหลังนำกลับผ่านเพจฟอลต์

ดังนั้น Working Set ที่ลดไม่จำเป็นต้องหมายถึง “แอปปล่อยแล้ว” และการเพิ่มไม่จำเป็นต้องหมายถึง “แอปเพิ่งจัดสรร”

กระแสทั่วไปที่เฉพาะ Working Set ขึ้นลงเพจที่ commit เดียวกันเข้า RAM เมื่อเข้าถึงครั้งแรก กลายเป็นไม่อยู่เมื่อ Trim และกลับเมื่อเข้าถึงอีก ขณะ Private Bytes ยังถูกนับตลอดเข้าถึงครั้งแรกTrim ภายใต้แรงดันหน่วยความจำเพจฟอลต์เมื่อเข้าถึงอีกเพจที่ commit เดียวกันอยู่ใน RAMไม่อยู่รวมใน Working Setไม่รวมใน Working Setนับใน Private Bytes ขณะยัง commit

ภาพ 5: Working Set ขึ้นลงตามการอยู่ แต่ Private Bytes ไม่ลดตราบที่ commit ของเพจเดียวกันยังอยู่

4.2. Working Set รวมเพจร่วม

หาก 10 โปรเซสใช้เพจโค้ด DLL เดียวกัน เพจนั้นอาจปรากฏใน Working Set ของแต่ละโปรเซส แม้ใน RAM กายภาพมีสำเนาเดียว ผลรวม Working Set เกิน RAM ที่ติดตั้งไม่ใช่สัญญาณปัญหาทันที

หากอยากเข้าใกล้ “RAM ที่โปรเซสนี้ครองอยู่คนเดียวตอนนี้” ให้ดู Private Working Set แม้กระนั้นก็ไม่ใช่ “หน่วยความจำทั้งหมดที่โปรเซสนั้นจัดสรร” — มันคือ เพจส่วนตัวที่อยู่ใน RAM ตอนนี้ อย่างเคร่งครัด

4.3. บังคับ Working Set ให้ลงไม่แก้การรั่ว

คุณใช้ EmptyWorkingSet หรือ SetProcessWorkingSetSize เพื่อไล่เพจออกจาก Working Set ของโปรเซสได้ แต่ไม่ใช่การปล่อย commit หรือปล่อยการอ้างอิงบนฮีป การใช้ RAM ที่เห็นลดลงขณะ Private Bytes คงที่ และการเข้าถึงถัดไปอาจกระตุ้นเพจฟอลต์ระลอก9

หากตัวเลข Task Manager หดเฉพาะทันทีหลังกดปุ่ม “ลดหน่วยความจำ” แล้วพุ่งกลับเมื่อกลับมาทำงาน อาจเป็นเพียง Working Set Trim ไม่ใช่ “การปล่อย” จริง

5. Private Bytes — ปริมาณ commit ที่เป็นของโปรเซส

Private Bytes คือปริมาณหน่วยความจำเสมือนที่ commit เฉพาะโปรเซสนั้น แทน Commit Charge ที่ใช้ร่วมกับโปรเซสอื่นไม่ได้ และไม่สนใจว่าอยู่ใน RAM ตอนนี้หรือไม่ ใน PROCESS_MEMORY_COUNTERS_EX ของ Microsoft PrivateUsage สอดคล้องกับค่านี้102

Win32 API ยังมีฟิลด์ชื่อสับสน PagefileUsage แต่เอกสารปัจจุบันนิยามว่าเป็น “Commit Charge ของโปรเซสนั้น” และระบุว่าเป็นค่าเดียวกับ PrivateUsage นั่นคือ Private Bytes 2GB ไม่ได้หมายถึง “เขียน 2GB ลง pagefile.sys”2

Private Bytes มักได้รับผลจากสิ่งต่อไปนี้

  • commit ของฮีปเนทีฟที่ HeapAlloc, malloc, new และคล้ายกันใช้
  • Private Data ที่ commit โดยตรงด้วย VirtualAlloc
  • บริเวณที่ commit ของฮีป GC .NET
  • ส่วนของสแตกเธรดที่ commit จริง
  • Commit Charge สำหรับทั้งวิวที่จองเมื่อแมปวิว copy-on-write (FILE_MAP_COPY)
  • บัฟเฟอร์ส่วนตัวที่ไลบรารีและ SDK อุปกรณ์ถือภายใน

ในวิว copy-on-write ที่สร้างด้วย FILE_MAP_COPY แต่ละเพจอาจกลายเป็นส่วนตัวในที่สุด ดังนั้นตอนแมป Windows จอง Commit Charge พอรองรับทั้งวิวด้วยเพจไฟล์ ด้วยเหตุนี้ System Commit และ Commit Charge ของโปรเซส (Private Bytes) อาจขึ้นเท่าขนาดทั้งวิว แม้ยังไม่มีการเขียนที่สร้างสำเนาส่วนตัวจริง11

5.1. ทำไม Private Bytes ไม่ลงหลัง free หรือ GC

แม้หน่วยความจำถูก “ปล่อย” จากมุมแอป รันไทม์หรือตัวจัดสรรฮีปอาจไม่ Decommit บริเวณนั้นคืน OS และเก็บไว้ใช้ซ้ำในอนาคต ในกรณีนั้น Private Bytes ยังสูงแม้บริเวณนั้นใช้ซ้ำได้ภายในแอป

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

ดังนั้น Private Bytes สูงอย่างเดียวไม่พิสูจน์การรั่ว สิ่งที่ควรดูคือการเปรียบเทียบตามเวลา

  1. ทำประมวลผลเดิมซ้ำจำนวนครั้งเท่ากัน
  2. รอเวลาเท่ากันหลังประมวลผล
  3. ตรวจว่า Private Bytes กลับสู่ระดับเดิม หรือราบที่ค่าคงที่
  4. ใช้ VMMap หรือดัมป์ฮีปตรวจว่าบริเวณหรือชนิดใดโต
ทำไม Private Bytes ไม่ลงหลัง free หรือ GCPrivate Bytes เปลี่ยนต่างกันตามว่าตัวจัดสรรคืนบริเวณที่แอปไม่ต้องการแล้วให้ OS หรือเก็บไว้ใช้ซ้ำDecommit / Releaseเก็บไว้ใช้ซ้ำแอปปล่อยบริเวณผ่าน free / GCตัวจัดสรรคืนให้ OS หรือไม่Commit Charge ลดPrivate Bytes ลงบริเวณยัง commitPrivate Bytes ราบสูงพูล แคช การแตกเป็นชิ้น

ภาพ 6: บริเวณที่ใช้ซ้ำได้ภายในแอปไม่เท่ากับ Commit ถูกคืนให้ OS

5.2. รูปแบบผู้สมัครแข็งของการรั่ว

การเพิ่มแบบต่อไปนี้ ที่พื้นไต่ขึ้นทุกวอบโหลดเป็น “บันได” น่าสนใจ

Private Bytes
  ^
  |                    ________
  |             ______|
  |      ______|
  |_____|
  +----------------------------> การทำประมวลผลเดิมซ้ำ

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

6. System Commit — “Committed X/Y” คืออะไรจริง ๆ

ตัวเลข “Committed X/Y” บนแท็บ [Performance] → [Memory] ของ Task Manager เป็นเมตริกทั้งระบบ

  • X: System Commit Charge — หน่วยความจำที่ commit ซึ่ง Windows สัญญาจะรองรับทั้งระบบตอนนี้
  • Y: System Commit Limit — เพดาน commit ที่ระบบรับได้

Commit Limit ประมาณจาก RAM กายภาพบวกผลรวมเพจไฟล์ทั้งหมด หากไม่มีเพจไฟล์จะออกมาน้อยกว่า RAM ที่ติดตั้งเล็กน้อย36

ความสัมพันธ์ของ System Commit Charge กับ Commit Limitcommit ต่อโปรเซส ส่วนร่วม และเคอร์เนลประกอบค่าปัจจุบัน X ขณะ RAM กายภาพและเพจไฟล์รองรับเพดาน YX เกิน Y ไม่ได้Private Commit ของแต่ละโปรเซสSystem Commit Charge - XCommit ของส่วนร่วมที่แบ็กด้วยเพจไฟล์Commit ของเคอร์เนลRAM กายภาพSystem Commit Limit - Yเพจไฟล์

ภาพ 7: X คือปริมาณที่สัญญาตอนนี้ และ Y คือเพดานที่รองรับสัญญานั้น — ไม่ใช่การแสดงการใช้เพจไฟล์

System Commit Charge รวมไม่เฉพาะผลรวม Private Bytes ของแต่ละโปรเซส แต่รวม Commit ของส่วนร่วมที่แบ็กด้วยเพจไฟล์ และ Commit ที่เคอร์เนลบริโภค ดังนั้นผลรวม Private Bytes ต่อโปรเซสอย่างเดียวอธิบาย X ไม่ครบ

6.1. Commit Charge ไม่ใช่การใช้เพจไฟล์

พิจารณาระบบที่มี RAM 16GB เพจไฟล์ 16GB และ Committed ที่ 20/31GB

20GB นั้นไม่ได้หมายถึง “เขียน 20GB ลงเพจไฟล์” เป็นปริมาณรวมที่ Windows สัญญาจะจัด RAM หรือแบ็กกิงเพจไฟล์เมื่อต้องการ สำหรับเพจส่วนตัวที่เขียนได้ เป็นต้น

ณ ขณะนั้นสถานะผสมต่อไปนี้อาจเป็นจริง

  • ส่วนใหญ่อยู่ใน RAM
  • บางส่วนถูกเพจออกไปเพจไฟล์
  • บางส่วน commit แล้วแต่ยังไม่เข้าถึงครั้งแรก
  • บางส่วนถูกบริโภคเป็น commit ฝั่งเคอร์เนล

หากอยากเห็นการใช้เพจไฟล์จริง ให้ตรวจ Paging File(*)\% Usage แยกจาก Commit แม้เอกสารของ Microsoft เองอธิบายว่าการใช้เพจไฟล์สูงอย่างเดียวไม่จำเป็นต้องเป็นปัญหาประสิทธิภาพ และควรวินิจฉัยร่วมกับการถึง Commit Limit, Modified Page List และ I/O เพจจริง6

6.2. จะเกิดอะไรเมื่อเข้าใกล้ Commit Limit

เมื่อ System Commit Charge ถึง Commit Limit คำขอ commit ใหม่รองรับไม่ได้ สิ่งนี้นำไปสู่การจัดสรรหน่วยความจำโปรเซสล้มเหลว แอปครैช และระบบไม่ตอบสนอง3

ที่นี่ X/Y ของ Commit สำคัญกว่า “RAM ว่าง” แม้คุณ Trim Working Set เพื่อว่าง RAM การถึง Commit Limit ไม่คลี่คลายจนกว่า Commit Charge เองจะลด

6.3. สามบทบาทของเพจไฟล์

เพจไฟล์มีบทบาทหลักดังนี้

  1. ขยาย Commit Limit
  2. ให้เพจที่ถูกแก้และใช้น้อยถูกเพจออกจาก RAM ได้
  3. รองรับครैชดัมป์ของระบบ ตามการตั้งค่า

การปิดเพจไฟล์ไม่ใช่กรณีง่ายว่า “I/O ดิสก์ลดเสมอแล้วทุกอย่างเร็วขึ้น” กลับกันมันลด Commit Limit ทำให้เพจที่ถูกแก้แต่ยังไม่ต้องการอยู่ค้างใน RAM ได้ง่ายขึ้น และอาจทำให้จับดัมป์ที่ต้องการเมื่อครैชไม่ได้36

ขนาดเพจไฟล์ที่เหมาะสมตัดสินจาก RAM ที่ติดตั้งอย่างเดียวไม่ได้ Microsoft เองอธิบายว่าสรุปทั่วไปไม่ได้ เพราะยอด System Commit Charge และชนิดครैชดัมป์ที่ต้องการต่างกันตามระบบ6

7. รายละเอียด RAM กายภาพ — อย่าตัดสินจาก Available ต่ำอย่างเดียว

RAM กายภาพไม่ได้ใช้เฉพาะ Working Set ของโปรเซสผู้ใช้

  • Working Set ของแต่ละโปรเซส
  • แคชไฟล์ระบบ
  • รายการเพจอย่าง Standby, Modified, Free และ Zeroed
  • Paged Pool / Nonpaged Pool ของเคอร์เนล
  • หน่วยความจำที่ไดรเวอร์อุปกรณ์ถือ
  • ที่เก็บการบีบหน่วยความจำ
  • บริเวณที่ใช้ร่วมหรือจองให้ GPU และอุปกรณ์อื่น
  • หน่วยความจำที่ฮาร์ดแวร์จอง

7.1. Available รวมแคชที่ใช้ซ้ำได้ด้วย

Available MBytes ของ Windows ไม่ใช่เพียง RAM ที่ไม่ใช้เลย เป็นเมตริกที่รวม Free และ Zeroed พร้อมเพจ Standby ที่ใช้ซ้ำได้เมื่อต้องการ12

  • Free: เพจที่ยังไม่ถูกจัดสรรให้จุดประสงค์ใด
  • Zeroed: เพจที่ถูกตั้งศูนย์เพื่อส่งต่อให้โปรเซสอื่นอย่างปลอดภัย
  • Standby: เพจที่ออกจาก Working Set แล้วแต่เนื้อหายังแคชใน RAM
  • Modified: เพจที่เนื้อหาเปลี่ยนและต้องเขียนกลับไปแบ็กกิงที่เหมาะก่อนใช้ซ้ำ
การเคลื่อนระหว่าง Working Set กับรายการเพจแสดงเพจที่ไม่เปลี่ยนไป Standby และเพจที่เปลี่ยนไป Modified แล้วเข้าถึงอีก เขียนกลับ และใช้ซ้ำถอดเพจที่ไม่เปลี่ยนถอดเพจที่เปลี่ยนเขียนกลับเสร็จเข้าถึงอีกใช้ซ้ำเพื่อจุดประสงค์อื่นตั้งศูนย์เข้าถึงหลังจัดสรรWorking Set - กำลังใช้Standby - ผู้สมัครใช้ซ้ำที่เก็บเนื้อหาModified - รอเขียนกลับจัดสรรให้จุดประสงค์อื่นFree - ไม่ได้ใช้Zeroed - พร้อมจัดสรรใหม่รวมใน Available

ภาพ 8: Available รวมไม่เฉพาะหน่วยความจำว่างสนิท แต่รวม Standby ที่ใช้ซ้ำได้เมื่อต้องการ

“ทิ้งแคชทั้งหมดเพื่อเพิ่ม RAM ว่าง” ไม่ใช่ชัยชนะเสมอ หากข้อมูลที่ต้องการยังอยู่ใน Standby การเข้าถึงอีกนำกลับ Working Set ได้เร็วโดยไม่อ่านดิสก์

ดังนั้นแม้ Free ต่ำใน Task Manager หาก Available พอและฮาร์ดเพจฟอลต์หรือการรอดิสก์ไม่เป็นปัญหา Windows อาจเพียงใช้ RAM เป็นแคชอย่างมีประสิทธิภาพ

7.2. เมื่อ RAM หดโดยไม่มีโปรเซสใหญ่

ไม่แปลกที่การใช้หน่วยความจำอธิบายไม่ได้แม้รวม Private Working Set ของทุกโปรเซส

  • แคชไฟล์และไฟล์แมปหน่วยความจำ
  • Nonpaged Pool / Paged Pool
  • เพจที่ไดรเวอร์ล็อก
  • เพจร่วม
  • การบีบหน่วยความจำ
  • การจัดสรรที่เกี่ยวกับการจำลองเสมือนหรือ GPU

ในกรณีนี้แทนที่จะจ้องรายการโปรเซสต่อไป ให้ตรวจ Use Counts, Processes, Priority Summary และ File Summary ใน RAMMap ของ Sysinternals RAMMap เป็นเครื่องมือทางการสำหรับแยกหน่วยความจำกายภาพตามจุดประสงค์ รายการเพจ และไฟล์13

หากเฉพาะ Nonpaged Pool โตต่อเนื่อง นั่นคือจุดที่ควรสงสัยการรั่วฝั่งไดรเวอร์หรือเคอร์เนล ไม่ใช่ Private Bytes ของแอปโหมดผู้ใช้

8. เพจฟอลต์ — จำนวนสูงอย่างเดียวไม่ผิดปกติ

Page Fault เกิดเมื่อโปรเซสเข้าถึงเพจที่ยังไม่อยู่ใน Working Set แม้ชื่อมีคำว่า “Fault” นี่ไม่ใช่ความล้มเหลวพิเศษ — เป็นกลไกปกติที่ขับหน่วยความจำเสมือน1

8.1. ซอฟต์เพจฟอลต์

แก้โดยไม่อ่านจากดิสก์

  • เพจยังอยู่ใน Standby หรือ Transition
  • เพจร่วมเดียวกันอยู่ใน Working Set ของโปรเซสอื่นแล้ว
  • เพจที่ commit ถูกเข้าถึงครั้งแรกและได้รับเพจศูนย์
  • การอ่านล่วงหน้าของตัวจัดการหน่วยความจำพาเข้า RAM แล้ว

ดังนั้น \Memory\Page Faults/sec ที่ใหญ่ไม่จำเป็นต้องหมายถึงมี I/O ดิสก์หรือความหน่วง

8.2. ฮาร์ดเพจฟอลต์

ต้องอ่านเนื้อหาจาก Backing Store บนดิสก์ แหล่งไม่จำกัดที่เพจไฟล์

  • โค้ดและข้อมูลใน .exe หรือ .dll
  • ไฟล์แมปหน่วยความจำ
  • เพจไฟล์
กิ่งของซอฟต์และฮาร์ดเพจฟอลต์เมื่อเข้าถึงเพจที่ไม่อยู่ใน Working Set จัดการเป็นซอฟต์เพจฟอลต์หากไม่ต้อง I/O ที่เก็บ หรือฮาร์ดเพจฟอลต์หากต้องไม่ - Standby ร่วม demand-zero ฯลฯใช่เข้าถึงเพจที่ไม่อยู่ใน Working Setต้อง I/O ที่เก็บหรือไม่ซอฟต์เพจฟอลต์เข้า Working Set โดยไม่อ่านดิสก์ฮาร์ดเพจฟอลต์อ่านจากที่ใดEXE / DLLไฟล์แมปหน่วยความจำเพจไฟล์เข้า Working Set หลังโหลด

ภาพ 9: ชื่อ “Page Fault” อย่างเดียวบอกไม่ได้ว่าเกิด I/O ดิสก์หรือไม่

Microsoft ระบุ \Memory\Pages/sec, \Memory\Page Reads/sec และ \Memory\Pages Input/sec เป็นตัวนับวัดฮาร์ดฟอลต์ การที่ค่าเหล่านี้สูงไม่จำเป็นต้องหมายถึงหน่วยความจำต่ำ จึงควรสัมพันธ์กับ Available MBytes ความหน่วงดิสก์ และเวลาตอบสนองจริง6

8.3. อย่าตั้งเกณฑ์ผ้าห่มเดียว

ค่าคงที่เช่น “เกิน 1000 Page Faults/sec คือผิดปกติ” เปลี่ยนความหมายตามที่เก็บ ขนาดเพจ ภาระงาน และความใกล้ของการเข้าถึง

ในทางปฏิบัติให้เรียงสิ่งต่อไปนี้บนไทม์ไลน์เดียวกัน

  • Memory\Available MBytes
  • Memory\Pages Input/sec
  • Memory\Page Reads/sec
  • ความหน่วงอ่าน / คิวของดิสก์เป้าหมาย
  • Working Set และ Private Bytes ของโปรเซสเป้าหมาย
  • เวลาประมวลผลของแอป หมดเวลา และการตอบสนอง UI

หาก Available ลดพร้อมโหลดขึ้น Pages Input/sec และการรอดิสก์ขึ้น และเวลาประมวลผลแย่ลง นั่นให้เหตุสงสัยการเพจจากแรงดันหน่วยความจำกายภาพ

9. ดูหน้าจอหรือเครื่องมือใดเพื่ออะไร

สิ่งที่อยากรู้ เมตริกที่ตรวจก่อน เครื่องมือหลัก
ปริมาณที่โปรเซสเป้าหมายมีใน RAM ตอนนี้ Working Set Task Manager, Process Explorer, Get-Process
ส่วนส่วนตัวของนั้น — RAM ของโปรเซส Private Working Set / Working Set - Private คอลัมน์ Details ของ Task Manager, Process Explorer, PerfMon
ปริมาณ commit ของโปรเซสเป้าหมาย Private Bytes / Commit Size Process Explorer, PerfMon, VMMap, Get-Process
ช่วงที่อยู่เสมือนของโปรเซส Virtual Bytes / Size Process Explorer, VMMap, Get-Process
หัว commit รวมของระบบ Committed Bytes / Commit Limit Task Manager [Performance], PerfMon
หัวการใช้ซ้ำของ RAM กายภาพ Available MBytes Task Manager, PerfMon
รายละเอียด Standby, Modified และแคชไฟล์ รายการเพจ / แยกตามจุดประสงค์ RAMMap
อะไรโตใน Private Bytes Heap / Private Data / Managed Heap ฯลฯ VMMap, WinDbg, ดัมป์เฉพาะรันไทม์
การเพจที่เกี่ยวกับดิสก์ Pages Input/sec, Page Reads/sec, ความหน่วงดิสก์ PerfMon, WPR/WPA
เลือกเครื่องมือสอบสวนหน่วยความจำ Windowsเครื่องมือที่ใช้ขึ้นกับว่าเป้าเป็นโปรเซสเดียวหรือทั้งระบบ จุดเวลาเดียวหรืออนุกรมเวลา และต้องไล่การถือในรันไทม์หรือไม่ใช่รายละเอียดจุดเดียวอนุกรมเวลาทั้งระบบรายละเอียด RAM กายภาพไทม์ไลน์รวม CPU I/O และการรอฮีป .NETฮีปเนทีฟคุณอยากแยกอะไรเป้าเป็นโปรเซสเดียวหรือไม่จุดเวลาเดียวหรืออนุกรมเวลาVMMapPerfMon / PowerShellรายละเอียด RAM กายภาพหรือไทม์ไลน์RAMMapWPR / WPAต้องไล่การถือในรันไทม์หรือไม่dotnet-dump / PerfViewWinDbg / Application Verifier

ภาพ 10: ตัดสินขอบเขตและไทม์ไลน์ก่อนทำให้เลือกเครื่องมือได้พอดี ไม่มากไม่น้อย

9.1. Task Manager

ใน Task Manager ให้ดูหน้าจอแยกกัน

  • [Processes] หรือ [Details]: ตระกูล Working Set และตระกูล Commit Size ของแต่ละโปรเซส
  • [Performance] → [Memory]: In use, Available, Committed, Cached, Paged pool, Non-paged pool ทั้งระบบ

อย่าตัดสินจากคอลัมน์ชื่อ “Memory” อย่างเดียว — คลิกขวาหัวคอลัมน์บนแท็บ [Details] แล้วเพิ่มคอลัมน์ที่ต้องการ เช่น Working Set, Peak Working Set และ Commit Size ชื่อคอลัมน์ต่างกันบ้างตามรุ่น Windows และภาษาแสดงผล ดังนั้น ยืนยันความหมายของคอลัมน์ก่อนบันทึก

9.2. จับอนุกรมเวลาด้วย PowerShell

หากรู้ ID ของโปรเซสเป้าหมาย คุณจับแนวโน้ม Working Set, Private Bytes และ Virtual Bytes พร้อมกันด้วย Get-Process ได้

param(
    [Parameter(Mandatory)]
    [int]$ProcessId,

    [int]$IntervalSeconds = 5,
    [int]$SampleCount = 60
)

$samples = for ($i = 0; $i -lt $SampleCount; $i++) {
    $process = Get-Process -Id $ProcessId -ErrorAction Stop

    [pscustomobject]@{
        Timestamp      = Get-Date -Format 'yyyy-MM-dd HH:mm:ss'
        ProcessId      = $process.Id
        WorkingSetMB   = [math]::Round($process.WorkingSet64 / 1MB, 1)
        PrivateBytesMB = [math]::Round($process.PrivateMemorySize64 / 1MB, 1)
        VirtualBytesMB = [math]::Round($process.VirtualMemorySize64 / 1MB, 1)
        Handles        = $process.HandleCount
        Threads        = $process.Threads.Count
    }

    Start-Sleep -Seconds $IntervalSeconds
}

$samples | Format-Table -AutoSize
$samples | Export-Csv .\memory-samples.csv -NoTypeInformation -Encoding utf8

Process.WorkingSet64 ของ .NET สอดคล้องกับ Working Set, PrivateMemorySize64 กับ Private Bytes และ VirtualMemorySize64 กับ Virtual Bytes141516

สำหรับแอปที่มีหลายอินสแตนซ์ ให้ตามด้วย PID ไม่ใช่ชื่อ สำหรับการเฝ้าดูระยะยาวที่การรีสตาร์ตเปลี่ยน PID ให้ออกแบบการเก็บให้บันทึกเวลาเริ่ม ชื่อบริการ และคล้ายกัน เพื่อไม่สับสนเป้า

9.3. วางระบบกับโปรเซสบนไทม์ไลน์เดียวกันด้วย PerfMon

การบันทึกอย่างน้อยสิ่งต่อไปนี้พร้อมกันทำให้การแยกง่ายขึ้นมาก

\Process(<เป้าหมาย>)\ID Process
\Process(<เป้าหมาย>)\Working Set
\Process(<เป้าหมาย>)\Working Set - Private
\Process(<เป้าหมาย>)\Private Bytes
\Process(<เป้าหมาย>)\Virtual Bytes

\Memory\Available MBytes
\Memory\Committed Bytes
\Memory\Commit Limit
\Memory\Pages Input/sec
\Memory\Page Reads/sec
\Memory\Pool Nonpaged Bytes
\Memory\Pool Paged Bytes

เมื่อหลายโปรเซสใช้ชื่อเดียวกัน หรือเกิดรีสตาร์ตระหว่างเฝ้าดู ชื่ออินสแตนซ์อย่างเดียว — Process(name) หรือ Process(name#N) — ตรึงเป้าไม่ได้ บันทึก ID Process ของแต่ละตัวอย่างด้วย และรับเฉพาะอินสแตนซ์ที่ค่าตรงกับ PID ที่ตาม เมื่อข้ามรีสตาร์ตที่เปลี่ยน PID ให้บันทึกเวลาที่สลับแยกด้วย

ชื่อตัวนับประสิทธิภาพ Windows อาจถูกแปลตามภาษาแสดงผล หากระบุชื่อภาษาอังกฤษตรง ๆ ใน PowerShell แล้วไม่พบ ให้เพิ่มตัวนับผ่าน GUI ของ PerfMon หรือตรวจชื่อในสภาพแวดล้อมท้องถิ่นด้วย Get-Counter -ListSet *

9.4. อย่าสับสนบทบาทของ VMMap กับ RAMMap

  • VMMap: แยกหน่วยความจำเสมือนและ Working Set ของหนึ่งโปรเซสเป็น Heap, Image, Mapped File, Private Data, Managed Heap เป็นต้น
  • RAMMap: แยก RAM กายภาพทั้งระบบตามจุดประสงค์ รายการเพจ โปรเซส และไฟล์

“อะไรทำให้ Private Bytes ของโปรเซสนี้โต” เป็นงานของ VMMap “RAM ที่รายการโปรเซสอธิบายไม่ได้ถูกใช้ทำอะไร” เป็นงานของ RAMMap1713

10. อ่านอาการจากชุดตัวเลข

รูปแบบที่สังเกต สมมติฐานแรก สิ่งที่ตรวจต่อ
Working Set ขึ้น Private Bytes คงที่ เข้าถึงเพจที่มีอยู่ครั้งแรก DLL ร่วม ไฟล์แมป แคชไฟล์ Image / Mapped File ของ VMMap, Pages Input/sec
Private Bytes ขึ้น Working Set คงที่ Commit ส่วนตัวโตแต่ไม่อยู่หรือถูก Trim Heap / Private Data / Managed Heap ของ VMMap
ทั้งคู่ขึ้นทันทีหลังเริ่ม แล้วราบ JIT แคช พูล การอุ่นเริ่มต้น ว่าโตอีกภายใต้โหลดเพิ่มเดิมหรือไม่
พื้น Private Bytes ขึ้นทุกวอบโหลด การรั่ว แคชไร้เพดาน หรือตัวจัดสรรที่ถือหลังปล่อย สแนปช็อต VMMap ก่อนหลัง ดัมป์ฮีป
เฉพาะ Working Set ลดฉับพลันแล้วกลับเมื่อทำงาน OS หรือแอป Trim Working Set Private Bytes, Pages Input/sec เวลาตอบสนอง
X ใน Committed X/Y เข้าใกล้ Y แรงดัน commit ทั้งระบบ ผู้บริโภค Private Bytes สูงสุด Paged/Nonpaged Pool การตั้งเพจไฟล์
Available ต่ำ Pages Input/sec และความหน่วงดิสก์สูง แรงดัน RAM กายภาพและการเพจหนัก ผู้บริโภค Working Set สูงสุด RAMMap ความสัมพันธ์ภาระงาน
การใช้ RAM สูงแต่ไม่มีโปรเซสใหญ่ แคช เพจร่วม พูลเคอร์เนล ไดรเวอร์ การบีบ ฯลฯ RAMMap, Pool Nonpaged/Paged Bytes
มี RAM ว่าง แต่เฉพาะแอป 32 บิตล้ม เพดานพื้นที่ที่อยู่เสมือนหรือการแตก Free/Reserved ของ VMMap การตั้ง LAA ของไฟล์ปฏิบัติการ
Private Bytes สูงแต่ไม่โตเมื่อประมวลผลซ้ำ พูลหรือแคชที่อาจถือลายน้ำสูง ขีดจำกัด พฤติกรรมใช้ซ้ำ ความคงที่หลังยอด

สิ่งสำคัญที่สุดของตารางนี้คือ อ่านเป็นชุด ไม่ใช่จากค่าเดียว

11. ขั้นตอนปฏิบัติสอบสวนการรั่วหน่วยความจำ

11.1. ตัดสินเงื่อนไขทำซ้ำและจุดคงที่ก่อน

“มันโตในไม่กี่วัน” อย่างเดียวเปรียบเทียบไม่ได้

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

ตัดสินทั้งหมดนี้

11.2. บันทึกโปรเซสและระบบพร้อมกัน

อย่างน้อยให้สิ่งต่อไปนี้อยู่ในล็อกที่ตราเวลาเดียวกัน

  • Working Set ของเป้า
  • Private Bytes ของเป้า
  • Virtual Bytes ของเป้า
  • Committed Bytes / Commit Limit ของระบบ
  • Available MBytes
  • Pages Input/sec
  • จำนวนแฮนเดิล จำนวนเธรด
  • จำนวนการทำงานหรือรายการที่ประมวลผล

หาก Private Bytes ของโปรเซสคงที่ขณะ Commit ของระบบยังโต คุณต้องขยายขอบเขตไปยังโปรเซสอื่น เคอร์เนล ไดรเวอร์ และส่วนร่วม

11.3. ตัดสินว่า “มิติ” ใดกำลังโตก่อน

  • เฉพาะ Working Set: เพจที่อยู่ ร่วมหรือมาจากไฟล์ Trim และโหลดใหม่
  • Private Bytes: commit ของโปรเซส
  • เฉพาะ Virtual Bytes: Reserve การแมป การแตกของพื้นที่ที่อยู่
  • เฉพาะ System Commit: รวมโปรเซสอื่นและฝั่งเคอร์เนล
  • Nonpaged Pool: ฝั่งไดรเวอร์/เคอร์เนล
  • Handles / GDI / USER: การรั่วของทรัพยากรที่ไม่ใช่หน่วยความจำ

ข้ามลำดับนี้แล้วกระโดดไปจับดัมป์ คุณจะอ่านภูเขาข้อมูลขณะเล็งผิดเป้า

11.4. ไปต่อที่รายละเอียด

  • โปรเซสเนทีฟ: VMMap, WinDbg, Application Verifier การตามรอยฮีป
  • .NET: dotnet-counters, dotnet-gcdump, dotnet-dump, PerfView
  • ทั้งระบบ: RAMMap, PerfMon, WPR/WPA
  • พูลเคอร์เนล: PoolMon, WinDbg

VMMap แสดงหน่วยความจำเสมือนที่ commit ของโปรเซส และ Working Set ที่จัดสรรให้แต่ละส่วน แยกตามชนิด ว่าคุณแคบการโตของ Private Bytes ลงถึง Heap, Private Data, Managed Heap หรือ Mapped File ได้ไกลเพียงใด ทำให้ต้นทุนการสอบสวนต่อต่างกันมาก17

11.5. หลังแก้ เปรียบเทียบแนวโน้มภายใต้เงื่อนไขเดิม

ค่ายอดต่างก่อนหลังแก้ยังไม่พอ หากค่าเริ่มต่าง การเปรียบเทียบพลิกง่าย

  • สถานะเริ่มเดียวกัน
  • ข้อมูลเข้าเดียวกัน
  • จำนวนการทำงานเดียวกัน
  • เวลารอเดียวกัน
  • ช่วงสุ่มตัวอย่างเดียวกัน

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

12. กล่าวใหม่ความเข้าใจผิดทั่วไป

ความเข้าใจผิด 1: Memory ของ Task Manager เท่ากับปริมาณทั้งหมดที่แอปจัดสรร

กล่าวใหม่: ตรวจว่าเป็นคอลัมน์ใด สำหรับตระกูล Working Set คือปริมาณที่อยู่ใน RAM ตอนนี้ สำหรับตระกูล Commit Size คือ commit ของโปรเซสนั้น

ความเข้าใจผิด 2: Private Bytes เท่ากับไบต์บนเพจไฟล์

กล่าวใหม่: Private Bytes คือ Commit Charge ส่วนตัว เป็นปริมาณที่สัญญาเชิงตรรกะซึ่งรวมทั้งเพจที่อยู่ใน RAM ตอนนี้และเพจที่จะถูกแบ็กด้วยเพจไฟล์เมื่อต้องการ

ความเข้าใจผิด 3: Commit X/Y เท่ากับการใช้เพจไฟล์ / ความจุเพจไฟล์

กล่าวใหม่: X คือ Commit Charge ทั้งระบบ และ Y คือ Commit Limit เพจไฟล์ขยาย Y แต่ X ไม่แปลงตรงเป็นการใช้บนดิสก์

ความเข้าใจผิด 4: Page Faults/sec สูงหมายถึงกำลังสลับไปดิสก์

กล่าวใหม่: รวมซอฟต์ฟอลต์ด้วย ตรวจ Pages Input/sec, Page Reads/sec และความหน่วงดิสก์เพื่อดูว่ามี I/O ดิสก์จริงหรือไม่

ความเข้าใจผิด 5: Free RAM ต่ำหมายถึงขาดหน่วยความจำ

กล่าวใหม่: ดู Available, Standby การเพจหนัก และเวลาตอบสนอง การเติม RAM ด้วยแคชที่ใช้ซ้ำได้เป็นเรื่องปกติ

ความเข้าใจผิด 6: ย่อ Working Set หมายถึงแก้การรั่วหน่วยความจำแล้ว

กล่าวใหม่: คุณอาจเพียงไล่เพจออกจาก RAM ตรวจว่า Private Bytes และสิ่งที่ถือในฮีปลดจริงหรือไม่

ความเข้าใจผิด 7: Private Bytes เพิ่มยืนยันการรั่ว

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

13. สรุป

  • “การใช้หน่วยความจำ” ของ Windows ไม่ใช่ตัวเลขเดียว คิดพื้นที่ที่อยู่ commit การอยู่ใน RAM และความใช้ร่วมแยกกัน
  • Working Set คือเพจที่อยู่ใน RAM ตอนนี้ รวมทั้ง Private และ Shared Private Working Set คือเพจส่วนตัวที่อยู่ในนั้น
  • Private Bytes คือ Commit Charge ของโปรเซส ไม่ใช่ปริมาณที่อยู่ใน RAM ตอนนี้ และไม่ใช่ปริมาณที่เขียนลงเพจไฟล์จริง
  • Committed X/Y คือ Commit Charge / Commit Limit ทั้งระบบ เพจไฟล์รองรับหลัก ๆ คือ Commit Limit การไล่เพจที่ถูกแก้ และครैชดัมป์
  • ที่อยู่เสมือนที่จอง เพจที่ commit และเพจที่ถูกแตะจริงแล้วเข้า Working Set เป็นขั้นแยก
  • Page Fault เป็นการทำงานปกติ และซอฟต์ฟอลต์ไม่อ่านจากดิสก์ ฮาร์ดฟอลต์ก็เกิดได้ไม่เฉพาะจากเพจไฟล์ แต่จาก EXE DLL หรือไฟล์แมป
  • การรั่วหน่วยความจำพิสูจน์ไม่ใช่ด้วยขนาด ณ จุดเดียว แต่ด้วยค่าพื้นและแนวโน้มหลังโหลดเดิม พร้อมรายละเอียด
  • เส้นทางพื้นฐาน: VMMap สำหรับรายละเอียดโปรเซสเดี่ยว RAMMap สำหรับ RAM กายภาพทั้งระบบ PerfMon สำหรับอนุกรมเวลา และเครื่องมือดัมป์เฉพาะสำหรับสิ่งในรันไทม์

ครั้งถัดไปที่สังเกตใน Task Manager ว่า “หน่วยความจำกำลังโต” ให้เริ่มด้วยการถามตัวเองดังนี้

สิ่งที่กำลังโตคือ Working Set, Private Bytes, Virtual Bytes หรือ System Commit

คำถามนั้นอย่างเดียวทำให้ทางเข้าการสอบสวนแม่นขึ้นมาก

บทความที่เกี่ยวข้อง

ด้านให้คำปรึกษาที่เกี่ยวข้อง

KomuraSoft LLC รับการสอบสวนสาเหตุที่แท้จริงซึ่งผสม PerfMon, VMMap, RAMMap, WinDbg และเครื่องมือวินิจฉัย .NET สำหรับหน่วยความจำแอป Windows ที่โต ประสิทธิภาพตกหลังทำงานต่อเนื่องนาน OutOfMemory ในโปรเซส 32 บิต และการขาดหน่วยความจำที่เกิดเฉพาะในสภาพแวดล้อมลูกค้า เราไม่หยุดที่เพียง “หน่วยความจำสูง” — เราแยกว่าบริเวณใดโต ผ่านการทำงานใด ทำไม และถูกอ้างหรือถือจากที่ใด

ลิงก์อ้างอิง

  1. Microsoft Learn, Working Set. ว่าด้วย Working Set ของโปรเซสเป็นชุดเพจที่อยู่ในหน่วยความจำกายภาพตอนนี้ รวมเพจร่วม ความต่างของซอฟต์และฮาร์ดเพจฟอลต์ เพจ Transition และการถอดเพจออกจาก Working Set  2 3 4 5

  2. Microsoft Learn, PROCESS_MEMORY_COUNTERS_EX2 structure. ว่าด้วยนิยามของ WorkingSetSize, PrivateWorkingSetSize, PrivateUsage และ SharedCommitUsage และว่า PagefileUsage กับ PrivateUsage ทั้งคู่แทน Commit Charge ของโปรเซส  2 3 4

  3. Microsoft Learn, Introduction to page files. ว่าด้วยเพจไฟล์รองรับการไล่เพจที่ถูกแก้ ครैชดัมป์ระบบ และการขยาย System Commit Limit นิยามของ System Commit Charge และ Commit Limit และการวัดผ่าน Task Manager และตัวนับประสิทธิภาพ  2 3 4

  4. Microsoft Learn, Page State. ว่าด้วยสถานะ Free, Reserved และ Committed ของเพจเสมือน และว่าเพจ Reserved ไม่มีที่เก็บกายภาพผูกและเข้าถึงไม่ได้  2

  5. Microsoft Learn, VirtualAlloc function. ว่าด้วยความต่างของ MEM_RESERVE กับ MEM_COMMIT การ commit ถูกคิดกับหน่วยความจำรวมและเพจไฟล์ของระบบ และเพจกายภาพจริงบางครั้งยังไม่ถูกจัดสรรจนเข้าถึงครั้งแรก  2 3

  6. Microsoft Learn, How to determine the appropriate page file size for 64-bit versions of Windows. ว่าด้วยขนาดเพจไฟล์ขึ้นกับยอด Commit Charge และความต้องการครैชดัมป์ ฮาร์ดเพจฟอลต์อ่านไม่เฉพาะจากเพจไฟล์แต่จาก EXE DLL และไฟล์แมปหน่วยความจำด้วย และตัวนับประสิทธิภาพที่เกี่ยวข้อง  2 3 4 5 6

  7. Microsoft Learn, Virtual Address Space. ว่าด้วยแต่ละโปรเซสมีพื้นที่ที่อยู่เสมือนและตารางเพจอิสระของตนเอง และที่อยู่เสมือนไม่ใช่ที่อยู่กายภาพเอง 

  8. Microsoft Learn, Memory Limits for Windows and Windows Server Releases. ว่าด้วยพื้นที่ที่อยู่เสมือนโหมดผู้ใช้ของโปรเซส 32 บิตมักเป็น 2GB และเป็น 2GB หรือ 4GB บน Windows 64 บิตตาม IMAGE_FILE_LARGE_ADDRESS_AWARE 

  9. Microsoft Learn, SetProcessWorkingSetSize function. ว่าด้วยค่าต่ำสุดและสูงสุดของ Working Set ไม่รับประกันการอยู่ การล้าง Working Set ได้ และการตั้งค่าหรือการกระทำที่มากเกินไปอาจทำให้ประสิทธิภาพระบบแย่ 

  10. Microsoft Learn, Memory Performance Information. ว่าด้วยความสอดคล้องระหว่างตัวนับประสิทธิภาพ Windows API จัดการหน่วยความจำ และการแสดงของ Task Manager รวม Working Set / Working Set - Private / Private Bytes ของอ็อบเจกต์ Process และ Committed Bytes / Commit Limit ของอ็อบเจกต์ System 

  11. Microsoft Learn, MapViewOfFile function. ว่าด้วย FILE_MAP_COPY ที่ทำให้ทุกเพจอาจ copy-on-write จึงจอง Commit Charge ทั้งวิวให้แบ็กด้วยเพจไฟล์ตอนแมป 

  12. Microsoft Learn, Understanding Node Metrics and Properties in HPC Cluster Manager. ว่าด้วย Available Physical Memory คำนวณเป็นผลรวมของรายการ Zeroed, Free และ Standby และความหมายของแต่ละรายการเพจ 

  13. Microsoft Sysinternals, RAMMap. ว่าด้วยการวิเคราะห์การใช้หน่วยความจำกายภาพของ Windows ตามจุดประสงค์ รายการเพจ โปรเซส ลำดับความสำคัญ เพจกายภาพ และไฟล์  2

  14. Microsoft Learn, Process.WorkingSet64 Property. ว่าด้วย WorkingSet64 คืน Working Set ของโปรเซสเป็นไบต์ สอดคล้องกับตัวนับประสิทธิภาพ Working Set ของอ็อบเจกต์ Process 

  15. Microsoft Learn, Process.PrivateMemorySize64 Property. ว่าด้วย PrivateMemorySize64 คืนหน่วยความจำของโปรเซสที่ใช้ร่วมกับโปรเซสอื่นไม่ได้ สอดคล้องกับตัวนับประสิทธิภาพ Private Bytes 

  16. Microsoft Learn, Process.VirtualMemorySize64 Property. ว่าด้วย VirtualMemorySize64 คืนปริมาณหน่วยความจำเสมือนที่จัดสรรให้โปรเซส สอดคล้องกับตัวนับประสิทธิภาพ Virtual Bytes 

  17. Microsoft Sysinternals, VMMap. ว่าด้วยการแยกหน่วยความจำเสมือนที่ commit ของโปรเซสตามชนิด และการแสดงหน่วยความจำกายภาพ (Working Set) ที่จัดสรรให้แต่ละส่วน พร้อมแผนที่หน่วยความจำละเอียด  2

บทความล่าสุดที่มีแท็กเดียวกัน เพื่อเจาะลึกหัวข้อใกล้เคียง

ความลึกของหน่วยความจำ Windows (ตอนที่ 2) — ชีวิตของเพจทางกายภาพ: ห้าบัญชีและเรื่องจริงของไฟล์เพจ

บทความนี้เชื่อมฐานข้อมูล PFN, Standby, Modified, การบีบอัดหน่วยความจำ และไฟล์เพจ เพื่ออธิบายว่าเพจทางกายภาพไปไหนหลังจากออกจาก Working Set.

แอปที่พังเมื่อรีซูมจากสลีป — อีเวนต์พลังงานของ Windows ทำงานอย่างไร และสร้างแอปธุรกิจที่รอดได้อย่างไร

เปิดแล็ปท็อปแล้วการเชื่อมต่อของแอปธุรกิจตาย — สาเหตุคือการออกแบบที่ไม่เคยคิดถึงสลีป บทความนี้ครอบคลุมลำดับการแจ้ง WM_POWERBROADCAST พฤติก...

DllMain และ Loader Lock — เหตุผลจริงที่ถูกบอกให้ "อย่าทำอะไรในการเริ่มต้น DLL"

ทำไมคุณต้องไม่เรียก LoadLibrary หรือซิงโครไนซ์กับเธรดอื่นจาก DllMain บทความนี้อธิบายจากแหล่งปฐมภูมิว่า loader lock ทำให้การแจ้ง DLL ทุกคร...

"ไม่ตอบสนอง" คืออะไรจริง ๆ — Windows ตัดสินว่าแอปแฮงอย่างไร และออกแบบอย่างไรให้ไม่แฮง

"ไม่ตอบสนอง" ของ Windows คือกลไกที่ OS ตัดสินว่าหน้าต่างไม่ได้ดึงข้อความเป็นเวลา 5 วินาทีแล้วแทนที่ด้วยหน้าต่างโกสต์ บทความนี้ครอบคลุมภาย...

WPR/WPA ในทางปฏิบัติ — บทนำการสอบสวนประสิทธิภาพทั้งระบบเมื่อ "พีซีทั้งเครื่องช้า"

ปัญหาประสิทธิภาพอย่าง "พีซีทั้งเครื่องช้า" หรือ "สตาร์ตช้า" ที่ Task Manager ตามไม่ทัน สอบสวนได้ด้วยการจับและอ่าน ETW เทรซทั้ง OS ด้วย WP...

หน้าเหล่านี้วางหัวข้อไว้ในบริบทที่กว้างขึ้นของบริการและการตัดสินใจ

บทความนี้เกี่ยวข้องโดยตรงกับบริการต่อไปนี้

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

คำถามที่มักพบในการปรึกษาเกี่ยวกับหัวข้อของบทความนี้

คอลัมน์ "Memory" ใน Task Manager แสดงหน่วยความจำทั้งหมดที่แอปจัดสรรหรือไม่
ไม่ Task Manager มีหลายคอลัมน์หน่วยความจำ — ตระกูล Working Set ตระกูล Private Working Set Commit Size และอื่น ๆ — และความหมายขึ้นกับหน้าจอและคอลัมน์ที่คุณดู Working Set คือเพจที่อยู่ใน RAM ตอนนี้ Private Bytes หรือ Commit Size คือปริมาณ commit ของโปรเซสนั้นเอง อย่าอ่านคอลัมน์ "Memory" เดียวเป็นความจุทั้งหมดที่แอปจัดสรร หรือเป็นขนาดของการรั่ว
Working Set ต่างจาก Private Bytes อย่างไร
Working Set คือปริมาณเพจที่โปรเซสนั้นมองเห็นและอยู่ใน RAM กายภาพตอนนี้ รวมเพจที่ใช้ร่วมได้เช่นโค้ด DLL และไฟล์ที่แมปหน่วยความจำ Private Bytes คือปริมาณหน่วยความจำที่ commit เฉพาะโปรเซสนั้น ไม่ว่าจะอยู่ใน RAM ตอนนี้หรือไม่ ทั้งคู่จึงไม่เท่ากัน และไม่มีอันใดใหญ่กว่าอีกอันเสมอ
"Committed 18/32GB" ใน Task Manager หมายความว่าเขียน 18GB ลงเพจไฟล์หรือไม่
ไม่ ตัวเลขซ้ายคือ commit รวมที่ระบบทั้งก้อนสัญญาจะรองรับตอนนี้ ตัวเลขขวาคือเพดาน commit ที่ระบบรับได้ เพดานประมาณจาก RAM บวกเพจไฟล์ แต่ยอดซ้ายทั้งก้อนไม่ได้วนอยู่บนเพจไฟล์ เพจที่ commit ส่วนใหญ่อยู่ใน RAM และบางเพจที่ commit ยังไม่เคยได้เพจกายภาพ ขณะที่เพจที่โหลดใหม่จากไฟล์ต้นได้ เช่น EXE DLL และไฟล์แมปหน่วยความจำ ไม่จำเป็นต้องเพิ่ม Private Commit เท่าที่เพิ่ม Working Set
เกิด OutOfMemory ได้แม้ยังมี RAM ว่างหรือไม่
ได้ การจัดสรรล้มเหลวได้จากเหตุอื่นนอกจาก RAM กายภาพ รวมถึงโปรเซส 32 บิตหมดพื้นที่ที่อยู่เสมือน ไม่มีช่วงที่อยู่ว่างต่อเนื่องขนาดที่ต้องการ เพดาน commit ของระบบ หรือขีดจำกัดเฉพาะของ Job Object หรือรันไทม์ โดยเฉพาะโปรเซส 32 บิตบน Windows 64 บิตมักจำกัดที่ 2GB ของพื้นที่ที่อยู่เสมือนโหมดผู้ใช้ เว้นแต่จะเป็น Large Address Aware
ปิดเพจไฟล์แล้ว Windows จะเร็วขึ้นหรือไม่
ไม่ควรถือเป็นกฎทั่วไป การปิดเพจไฟล์ลดเพดาน commit ของระบบ ทำให้ไล่เพจที่ถูกแก้แต่ไม่ได้ใช้ออกจาก RAM ยากขึ้น และกระทบการตั้งค่าครैชดัมป์ ขนาดเพจไฟล์ควรวัดจากยอด commit charge และครैชดัมป์ที่ต้องการ ไม่ใช่การตั้งค่าที่ปิดโดยไม่มีเหตุ
Page Faults/sec สูงหมายความว่าระบบขาดหน่วยความจำหรือไม่
บอกจากแค่นั้นไม่ได้ เพจฟอลต์มีซอฟต์ฟอลต์ ซึ่งแก้จากเพจ Standby ใน RAM หรือเพจที่ใช้ร่วมกับโปรเซสอื่น และฮาร์ดฟอลต์ ซึ่งอ่านจากดิสก์ แทนที่จะดู Page Faults/sec โดด ๆ ให้ดู Pages Input/sec, Page Reads/sec, Available MBytes ความหน่วงดิสก์ และเวลาประมวลผลร่วมกันบนไทม์ไลน์เดียวกัน

โปรไฟล์ผู้เขียน

หน้าแนะนำผู้เขียนบทความ

Go Komura

ผู้แทนของ KomuraSoft LLC

เชี่ยวชาญด้านการพัฒนาซอฟต์แวร์ Windows ที่ปรึกษาเทคนิค และการตรวจสอบบั๊ก โดยเฉพาะโปรเจกต์ที่มีระบบเดิมและบั๊กที่ทำซ้ำได้ยาก

ลิงก์สาธารณะ

กลับไปยังบล็อก