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

หน่วยความจำรั่ว

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

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

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

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

หน่วยความจำจะยังคงถูกจองไว้จนกว่าโปรแกรมจะจบการทำงาน ทำให้ทรัพยากรถูกใช้อย่างสูญเปล่า

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

int main(void) {
    int *p = malloc(sizeof(int));
    *p = 5;
    printf("%d\n", *p);
    free(p);
    return 0;
}

การสูญเสียตัวชี้

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

บล็อกแรกจะไม่สามารถเข้าถึงได้อีก

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

int main(void) {
    int *p = malloc(sizeof(int));
    free(p);
    p = malloc(sizeof(int));
    *p = 10;
    printf("%d\n", *p);
    free(p);
    return 0;
}

หน่วยความจำรั่วในลูป

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

วิธีแก้คือคืนหน่วยความจำก่อนที่รอบถัดไปจะเขียนทับตัวชี้

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

int main(void) {
    for (int i = 0; i < 3; i++) {
        int *p = malloc(sizeof(int));
        *p = i;
        printf("%d ", *p);
        free(p);
    }
    printf("\n");
    return 0;
}

การส่งค่ากลับก่อนกำหนดทำให้หน่วยความจำรั่ว

การใช้ return ก่อนกำหนดหลังการจองหน่วยความจำอาจทำให้ข้ามขั้นตอนล้างทรัพยากรได้ ต้องคืนหน่วยความจำในทุกเส้นทางออกจากฟังก์ชันเสมอ

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

int process(int bad) {
    int *p = malloc(sizeof(int));
    if (bad) {
        free(p);
        return -1;
    }
    *p = 42;
    int r = *p;
    free(p);
    return r;
}

int main(void) {
    printf("%d\n", process(0));
    return 0;
}

รูปแบบการล้างทรัพยากรด้วย goto

ป้ายกำกับสำหรับล้างทรัพยากรเพียงจุดเดียวที่เข้าถึงด้วย goto ช่วยให้มีจุดเดียวสำหรับคืนหน่วยความจำทั้งหมด และหลีกเลี่ยงการเรียกใช้ free ซ้ำ

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

int main(void) {
    int rc = 1;
    int *p = malloc(sizeof(int));
    if (!p) goto done;
    *p = 7;
    printf("%d\n", *p);
    rc = 0;
done:
    free(p);
    return rc;
}

จับคู่กับการจองทุกครั้ง

กฎที่ง่ายที่สุดคือ สำหรับ malloc, calloc หรือ realloc แต่ละครั้ง ต้องมี free ที่สอดคล้องกันเพียงครั้งเดียว

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

int main(void) {
    char *a = malloc(8);
    char *b = calloc(4, sizeof(char));
    a[0] = 'x';
    printf("%c %d\n", a[0], b[0]);
    free(a);
    free(b);
    return 0;
}

การคืนหน่วยความจำที่จองซ้อนกัน

หากโครงสร้างข้อมูลเป็นเจ้าของหน่วยความจำบนฮีป ให้คืนหน่วยความจำของตัวชี้ภายในก่อน แล้วจึงคืนบล็อกภายนอก

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

typedef struct {
    int *data;
} Box;

int main(void) {
    Box *b = malloc(sizeof(Box));
    b->data = malloc(3 * sizeof(int));
    b->data[0] = 1;
    printf("%d\n", b->data[0]);
    free(b->data);
    free(b);
    return 0;
}

การคืนหน่วยความจำของอาร์เรย์ตัวชี้

เมื่อคุณจองอาร์เรย์ของตัวชี้ และแต่ละรายการเป็นการจองแยกกัน ให้คืนหน่วยความจำของทุกรายการก่อน แล้วจึงคืนหน่วยความจำของอาร์เรย์

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

int main(void) {
    int n = 3;
    int **rows = malloc(n * sizeof(int *));
    for (int i = 0; i < n; i++) {
        rows[i] = malloc(2 * sizeof(int));
        rows[i][0] = i;
    }
    for (int i = 0; i < n; i++) free(rows[i]);
    free(rows);
    printf("freed all rows\n");
    return 0;
}

วินัยด้านความเป็นเจ้าของ

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

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

char *make_greeting(void) {
    char *s = malloc(6);
    s[0]='h'; s[1]='i'; s[2]='\0';
    return s;
}

int main(void) {
    char *g = make_greeting();
    printf("%s\n", g);
    free(g);
    return 0;
}

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

เครื่องมืออย่าง Valgrind และ AddressSanitizer รายงานหน่วยความจำรั่วโดยติดตามการจองทุกครั้ง และแสดงรายการที่ไม่เคยถูกคืน

เครื่องมือเหล่านี้จำเป็นต่อการตรวจสอบโปรแกรมจริง

วงจรชีวิตการจองหน่วยความจำที่สะอาด

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

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

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

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

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

ทบทวน

คุณได้เรียนรู้วิธีป้องกันหน่วยความจำรั่ว:

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

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

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

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

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

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

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

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

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

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

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

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

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

  1. malloc และ free
  2. calloc และ realloc
  3. หน่วยความจำรั่ว
  4. พอยน์เตอร์ลอย
← กลับไปที่ C Academy