eryksun ได้ตอบคำถาม # 1 แล้วและฉันได้ตอบคำถาม # 3 (เดิม # 4) แต่ตอนนี้เรามาตอบคำถาม # 2:
ทำไมถึงปล่อย 50.5mb โดยเฉพาะ - จำนวนเงินที่ปล่อยตาม?
สิ่งที่มันขึ้นอยู่นั้นคือความบังเอิญทั้งชุดใน Python และmalloc
ยากที่จะคาดเดาได้
อันดับแรกขึ้นอยู่กับวิธีการวัดหน่วยความจำคุณอาจวัดได้เฉพาะหน้าที่แมปลงในหน่วยความจำเท่านั้น ในกรณีนี้เมื่อใดก็ตามที่เพจเจอร์ถูกสลับหน้าออกไปโดยเพจเจอร์หน่วยความจำจะแสดงเป็น "ว่าง" แม้ว่าจะไม่ได้รับอิสระก็ตาม
หรือคุณอาจกำลังวัดหน้าที่ใช้งานอยู่ซึ่งอาจหรือไม่นับหน้าที่จัดสรร แต่ไม่เคยสัมผัส (บนระบบที่จัดสรรมากเกินไปในแง่ดีเช่น linux) หน้าที่จัดสรร แต่ติดแท็กMADV_FREE
เป็นต้น
หากคุณกำลังวัดหน้าที่จัดสรรจริงๆ (ซึ่งจริงๆแล้วไม่ใช่สิ่งที่มีประโยชน์มากนัก แต่ดูเหมือนว่าจะเป็นสิ่งที่คุณกำลังถามถึง) และเพจต่างๆได้ถูกยกเลิกการจัดสรรแล้วจริงๆสองสถานการณ์ที่อาจเกิดขึ้นได้: ไม่ว่าคุณจะ เคยใช้brk
หรือเทียบเท่ากับการลดขนาดกลุ่มข้อมูล (หายากมากในปัจจุบัน) หรือคุณเคยใช้munmap
หรือคล้ายกับการปล่อยกลุ่มที่แมป (นอกจากนี้ยังมีทางทฤษฎีแตกต่างเล็ก ๆ น้อย ๆ หลังในการที่จะมีวิธีการที่จะปล่อยเป็นส่วนหนึ่งของแมปส่วน-เช่นขโมยมันด้วยMAP_FIXED
สำหรับMADV_FREE
ส่วนที่คุณ unmap ทันที.)
แต่โปรแกรมส่วนใหญ่ไม่ได้จัดสรรสิ่งต่างๆออกจากหน้าหน่วยความจำโดยตรง พวกเขาใช้malloc
ตัวจัดสรรสไตล์ เมื่อคุณเรียกfree
ใช้ผู้จัดสรรจะปล่อยเพจไปยังระบบปฏิบัติการได้ก็ต่อเมื่อคุณเพิ่งพบfree
อ็อบเจ็กต์สุดท้ายในการแมป (หรือใน N หน้าสุดท้ายของกลุ่มข้อมูล) ไม่มีทางที่แอปพลิเคชันของคุณสามารถคาดการณ์ได้อย่างสมเหตุสมผลหรือแม้กระทั่งตรวจพบว่าเกิดขึ้นล่วงหน้า
CPython นี้ทำให้แม้กระทั่งความซับซ้อนมากขึ้นมันมีกำหนดเอง 2 malloc
ระดับวัตถุจัดสรรด้านบนของการจัดสรรหน่วยความจำที่กำหนดเองที่ด้านบนของ (ดูความคิดเห็นที่มาสำหรับคำอธิบายโดยละเอียดเพิ่มเติม) และยิ่งไปกว่านั้นแม้ในระดับ C API Python น้อยกว่ามากคุณยังไม่สามารถควบคุมได้โดยตรงเมื่อมีการยกเลิกการจัดสรรออบเจ็กต์ระดับบนสุด
ดังนั้นเมื่อคุณปล่อยวัตถุคุณจะรู้ได้อย่างไรว่ามันจะปล่อยหน่วยความจำไปยัง OS หรือไม่? ก่อนอื่นคุณต้องรู้ว่าคุณได้เผยแพร่ข้อมูลอ้างอิงล่าสุดแล้ว (รวมถึงข้อมูลอ้างอิงภายในที่คุณไม่รู้จัก) เพื่อให้ GC ยกเลิกการจัดสรร (ซึ่งแตกต่างจากการใช้งานอื่น ๆ อย่างน้อย CPython จะยกเลิกการจัดสรรอ็อบเจ็กต์ทันทีที่ได้รับอนุญาต) ซึ่งโดยปกติจะยกเลิกการจัดสรรอย่างน้อยสองสิ่งในระดับถัดไปลงมา (เช่นสำหรับสตริงคุณกำลังปล่อยPyString
อ็อบเจ็กต์และสตริงบัฟเฟอร์ )
ถ้าคุณทำ deallocate วัตถุที่จะรู้ว่านี่เป็นสาเหตุที่ทำให้ลดลงในระดับถัดไป deallocate บล็อกของการจัดเก็บวัตถุที่คุณต้องรู้ว่ารัฐจัดสรรภายในของวัตถุเช่นเดียวกับวิธีการที่จะดำเนินการ (เห็นได้ชัดว่าไม่สามารถเกิดขึ้นได้เว้นแต่คุณจะยกเลิกการจัดสรรสิ่งสุดท้ายในบล็อกและถึงอย่างนั้นก็อาจไม่เกิดขึ้น)
ถ้าคุณทำ deallocate บล็อกของการจัดเก็บวัตถุที่จะรู้ว่าเรื่องนี้ทำให้เกิดการfree
โทรที่คุณต้องรู้สถานะภายในของตัวจัดสรร PyMem เช่นเดียวกับวิธีการที่จะดำเนินการ (อีกครั้งคุณต้องจัดสรรบล็อกที่ใช้งานล่าสุดภายในmalloc
ภูมิภาค ed และถึงอย่างนั้นก็อาจไม่เกิดขึ้น)
ถ้าคุณทำ ภูมิภาคเอ็ดที่จะรู้ว่าเรื่องนี้ทำให้เกิดการหรือเทียบเท่า (หรือ), คุณต้องรู้ว่ารัฐภายในของเช่นเดียวกับวิธีการที่จะดำเนินการ และอันนี้ไม่เหมือนที่อื่นคือเฉพาะแพลตฟอร์ม (และอีกครั้งโดยทั่วไปคุณจะต้องจัดสรรการใช้งานครั้งสุดท้ายภายในกลุ่มและถึงอย่างนั้นก็อาจไม่เกิดขึ้น)free
malloc
munmap
brk
malloc
malloc
mmap
ดังนั้นหากคุณต้องการที่จะเข้าใจว่าทำไมมันถึงปล่อย 50.5mb ได้คุณจะต้องติดตามจากด้านล่างขึ้นบน เหตุใดจึงmalloc
ยกเลิกการแมปเพจที่มีมูลค่า 50.5MB เมื่อคุณทำการfree
โทรอย่างน้อยหนึ่งครั้ง(อาจมากกว่า 50.5MB เล็กน้อย) คุณต้องอ่านแพลตฟอร์มของคุณmalloc
จากนั้นเดินตามตารางและรายการต่างๆเพื่อดูสถานะปัจจุบัน (ในบางแพลตฟอร์มอาจใช้ประโยชน์จากข้อมูลระดับระบบซึ่งแทบจะเป็นไปไม่ได้เลยที่จะจับภาพโดยไม่ต้องทำสแนปชอตของระบบเพื่อตรวจสอบแบบออฟไลน์ แต่โชคดีที่นี่ไม่ใช่ปัญหา) จากนั้นคุณต้อง ทำสิ่งเดียวกันใน 3 ระดับข้างต้นนั้น
ดังนั้นคำตอบเดียวที่เป็นประโยชน์สำหรับคำถามคือ "เพราะ"
เว้นแต่คุณจะทำการพัฒนาแบบ จำกัด ทรัพยากร (เช่นการพัฒนาแบบฝังตัว) คุณไม่มีเหตุผลที่จะสนใจรายละเอียดเหล่านี้
และหากคุณกำลังทำการพัฒนาแบบ จำกัด ทรัพยากรการรู้รายละเอียดเหล่านี้ก็ไร้ประโยชน์ คุณต้องทำ end-run รอบ ๆ ทุกระดับและโดยเฉพาะmmap
หน่วยความจำที่คุณต้องการในระดับแอปพลิเคชัน (อาจใช้ตัวจัดสรรโซนเฉพาะแอปพลิเคชันที่เข้าใจง่ายและเข้าใจได้ดีในระหว่างนั้น)