2014-07-24 14 views
5

Tôi đang phát triển một dự án trong C và tôi cần giải phóng bộ nhớ được cấp phát và cũng đóng tất cả các tệp đang mở trước khi thoát.Tồn tại một cách để giải phóng bộ nhớ trong atexit hoặc tương tự mà không sử dụng các biến toàn cầu?

Tôi quyết định triển khai chức năng clean sẽ thực hiện tất cả những thứ này và gọi nó bằng atexit vì có rất nhiều tình huống thoát có thể xảy ra.

Vấn đề là atexit không cho phép tôi đặt chức năng với thông số, vì vậy tôi không thể gửi tới clean các con trỏ cần được giải phóng vào cuối quá trình.

Vì vậy, tôi cần phải khai báo là biến toàn cầu, mỗi con trỏ có thể cần được giải phóng và mọi tệp có thể còn mở trong chương trình? (Tôi đã làm điều đó nhưng không có vẻ tốt) hoặc không tồn tại một chức năng tương tự như atexit cho phép gửi các tham số? hoặc nhiều hơn có lẽ có một cách khác mà tôi đang mất tích?

+1

Bạn chỉ cần một biến trỏ đến hồ bơi bộ nhớ. Điều đó có vẻ chấp nhận được. – this

+2

Nếu bạn đang sử dụng hệ điều hành tiêu dùng hiện đại thì tất cả các tài nguyên sẽ được phát hành khi bạn thoát. Điều đó có nghĩa là tất cả bộ nhớ được phân bổ sẽ được giải phóng, tất cả các tệp đang mở sẽ bị đóng, v.v. –

+1

Ngoài ra, nếu bạn có, ví dụ: các tệp cần phải mở trong suốt quá trình chạy, sau đó bạn cũng có thể truy cập vào nhiều vị trí và điều đó có nghĩa là nó đã là biến toàn cầu hoặc ít nhất toàn cục trong một đơn vị dịch, và sau đó bạn có thể đóng chức năng tệp đó được gọi từ hàm 'clean_all' toàn cục. Cùng với bộ nhớ bạn phân bổ. –

Trả lời

4

Sử dụng một con trỏ tĩnh bên trong một hàm:

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

void atexit_clean(void *data); 

static void clean(void) 
{ 
    atexit_clean(NULL); 
} 

void atexit_clean(void *data) 
{ 
    static void *x; 

    if (data) { 
     x = data; 
     atexit(clean); 
    } else { 
     free(x); 
    } 
} 

int main(void) 
{ 
    int *a = malloc(sizeof(int)); 

    atexit_clean(a); 
    return 0; 
} 

Một phương pháp sử dụng một biến toàn cầu duy nhất: bạn có thể lưu trữ tất cả các đối tượng được giải phóng trong một mảng của con trỏ hoặc một danh sách liên kết, ví dụ này sử dụng realloc (không kiểm tra (m/tái) alloc cho ngắn gọn):

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

static void **vclean; 
static size_t nclean; 

void atexit_add(void *data) 
{ 
    vclean = realloc(vclean, sizeof(void *) * (nclean + 1)); 
    vclean[nclean++] = data; 
} 

void clean(void) 
{ 
    size_t i; 

    for (i = 0; i < nclean; i++) { 
     free(vclean[i]); 
    } 
    free(vclean); 
} 

int main(void) 
{ 
    int *a, *b, *c; 
    double *d; 
    int e = 1; 

    atexit(clean); 
    a = &e; 
    b = malloc(sizeof(int)); 
    atexit_add(b); 
    c = malloc(sizeof(int)); 
    atexit_add(c); 
    d = malloc(sizeof(double)); 
    atexit_add(d); 
    return 0; 
} 
+0

Bạn nên di chuyển 'atexit (clean_all);' vào đầu hàm 'main()'. Đối với một ví dụ thực tế có thể có các hoạt động chấm dứt chương trình giữa các cuộc gọi đến 'atexit_add()'. – kay

+0

@Kay, điều đó phụ thuộc vào việc bạn có muốn để lại một cách sạch sẽ hoặc hủy bỏ, nhưng nói chung bạn đã đúng, đã chỉnh sửa. –

+0

'atexit_add()' nên kiểm tra lỗi 'realloc()' và trả về chỉ báo lỗi cho người gọi. –

3

không có cách nào để vượt qua bất kỳ thông số để atexit(), vì vậy bạn đang mắc kẹt sử dụng các biến toàn cầu.

Khi chương trình của bạn kết thúc bình thường, thông qua exit() hoặc bằng cách trở về từ main(), nó sẽ tự động tuôn ra và đóng mọi luồng mở và (trong phần lớn hệ điều hành) bộ nhớ được cấp phát miễn phí. Tuy nhiên, thực hành tốt là dọn sạch tài nguyên của bạn một cách rõ ràng trước khi chương trình chấm dứt, bởi vì nó thường dẫn đến một chương trình có cấu trúc hơn. Đôi khi cách sạch nhất để viết chương trình của bạn là chỉ cần thoát ra và để phần dọn dẹp thực hiện.

Nhưng được cảnh báo rằng bạn nên luôn luôn kiểm tra giá trị trả lại là fclose(). Xem "What are the reasons to check for error on close()?" để biết giai thoại về những gì có thể xảy ra khi bạn không làm như vậy.

+1

Chỉ cần lưu ý rằng tiêu chuẩn C không * yêu cầu * triển khai bộ nhớ được cấp phát miễn phí. Thật vậy, một vấn đề thường gặp đối với dòng TI-89 là các chương trình C không dọn dẹp trước khi thoát, và hệ điều hành đã làm * không * dọn dẹp, do đó việc thực hiện lặp lại một chương trình bị rò rỉ sẽ làm cạn kiệt RAM trên máy tính. –

Các vấn đề liên quan