C Academy · บทเรียน

คืนหน่วยความจำและหลีกเลี่ยงการรั่วไหล

ล้างทรัพยากรอย่างถูกต้อง

บทเรียน 4 จาก 413 ขั้นตอน

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

ทุก malloc ต้องมี free

หน่วยความจำบนฮีพจะยังคงถูกจองไว้จนกว่าคุณจะคืนหน่วยความจำด้วย free หากคุณทำพอยน์เตอร์เพียงตัวเดียวที่ชี้ไปยังบล็อกหายไปโดยไม่คืนหน่วยความจำ หน่วยความจำนั้นจะรั่วไหล

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

int *a = malloc(100 * sizeof(*a));
/* ... use a ... */
free(a);

สิ่งที่ free ทำจริง ๆ

free(p) คืนบล็อกให้ตัวจัดสรรหน่วยความจำ เพื่อให้นำกลับมาใช้ได้ แต่ไม่ได้เปลี่ยนค่าของ p เอง

หลังเรียก free แล้ว p ยังคงชี้ไปยังที่อยู่เดิม ซึ่งใช้ไม่ได้อีกต่อไป การเข้าถึงที่อยู่นั้นมีพฤติกรรมที่ไม่กำหนด

free(p);
/* p is now a dangling pointer */

กับดักพอยน์เตอร์ลอย

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

วิธีป้องกันง่าย ๆ คือกำหนดพอยน์เตอร์เป็น NULL ทันทีหลังคืนหน่วยความจำ

free(a);
a = NULL;   /* now misuse is a clean NULL deref, easier to catch */

การคืนหน่วยความจำซ้ำมีพฤติกรรมไม่กำหนด

การเรียก free สองครั้งกับบล็อกเดิมจะทำให้สถานะภายในของตัวจัดสรรหน่วยความจำเสียหาย และมักทำให้โปรแกรมหยุดทำงาน

การกำหนดพอยน์เตอร์เป็น NULL หลังเรียก free ครั้งแรกช่วยป้องกันได้ เพราะ free(NULL) ปลอดภัยตามข้อกำหนดและไม่ทำอะไร

free(a);
a = NULL;
free(a);   /* free(NULL) is a harmless no-op */

คืนหน่วยความจำเฉพาะสิ่งที่ malloc จัดสรร

ส่งให้ free เฉพาะพอยน์เตอร์ที่มาจาก malloc calloc หรือ realloc เท่านั้น

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

int x = 5;
/* free(&x);   WRONG: x is on the stack */
int *p = malloc(sizeof(int));
free(p);        /* correct */

หน่วยความจำรั่วจากการคืนค่าก่อนกำหนด

การรั่วไหลที่พบได้บ่อยคือ จัดสรรหน่วยความจำแล้วพบเส้นทางข้อผิดพลาดที่คืนค่าก่อนจะคืนหน่วยความจำ ทำให้บล็อกนั้นสูญหาย

ตรวจสอบให้แน่ใจว่าเส้นทางออกทุกเส้นทางที่เป็นเจ้าของหน่วยความจำได้คืนหน่วยความจำก่อน

int *a = malloc(n * sizeof(*a));
if (something_failed) {
    free(a);   /* don't forget this before returning */
    return -1;
}

โปรแกรมจัดสรรและคืนหน่วยความจำอย่างเรียบร้อย

โปรแกรมนี้จัดสรร ใช้งาน และคืนหน่วยความจำในทุกเส้นทาง โดยไม่มีหน่วยความจำรั่วไหล

#include <stdio.h>
#include <stdlib.h>

int main(void) {
    int n = 4;
    int *a = malloc(n * sizeof(*a));
    if (!a) return 1;
    for (int i = 0; i < n; i++) a[i] = i + 1;
    int sum = 0;
    for (int i = 0; i < n; i++) sum += a[i];
    printf("%d\n", sum);
    free(a);
    a = NULL;
    return 0;
}

การคืนหน่วยความจำของการจัดสรรแบบซ้อนกัน

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

หากคืนบล็อกด้านนอกก่อน ที่อยู่ของบล็อกด้านในจะสูญหายและทำให้บล็อกเหล่านั้นรั่วไหล

for (size_t i = 0; i < rows; i++)
    free(grid[i]);   /* free each row first */
free(grid);          /* then the array of pointers */

เจ้าของหนึ่งรายต่อหนึ่งบล็อก

กำหนดว่าส่วนใดของโค้ดเป็นเจ้าของการจัดสรรแต่ละรายการและรับผิดชอบการคืนหน่วยความจำ

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

ตรวจหาหน่วยความจำรั่วด้วยเครื่องมือ

คุณไม่จำเป็นต้องค้นหาหน่วยความจำรั่วด้วยตาเปล่า เครื่องมืออย่าง valgrind หรือ AddressSanitizer สามารถรายงานหน่วยความจำรั่วและการคืนหน่วยความจำที่ไม่ถูกต้องพร้อมหมายเลขบรรทัด

คอมไพล์ด้วย -g แล้วเรียกใช้ผ่านเครื่องมือ เพื่อดูได้อย่างแน่ชัดว่าส่วนใดไม่ได้รับการคืนหน่วยความจำ

/* gcc -g -fsanitize=address prog.c && ./a.out */
/* or: valgrind --leak-check=full ./a.out */

คืนหน่วยความจำย้อนลำดับการเตรียมพร้อม

แนวปฏิบัติที่เชื่อถือได้คือ ในฟังก์ชันที่ขอใช้ทรัพยากรหลายรายการ ให้คืนทรัพยากรในลำดับย้อนกลับจากที่ขอมา

วิธีนี้สอดคล้องกับลำดับการสร้างสิ่งที่ต้องพึ่งพากัน และทำให้การล้างข้อมูลคาดเดาได้

char *buf = malloc(64);
int  *idx = malloc(64 * sizeof(int));
/* ... use them ... */
free(idx);   /* free last-acquired first */
free(buf);

ตรวจสอบความเข้าใจอย่างรวดเร็ว

ทดสอบความเข้าใจเกี่ยวกับการคืนหน่วยความจำของคุณ

ทบทวน

จับคู่การจัดสรรทุกครั้งกับ free เพียงหนึ่งครั้งในทุกเส้นทางของโค้ด

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  1. จัดสรรอาร์เรย์
  2. ขยายด้วย realloc
  3. ชนิดเวกเตอร์ที่นำกลับมาใช้ได้
  4. คืนหน่วยความจำและหลีกเลี่ยงการรั่วไหล
← กลับไปที่ C Academy