Lập trình

Lập trình

Thứ Bảy, 14 tháng 6, 2014

Bản chất của việc cấp phát bộ nhớ động và giải phóng bộ nhớ

Nguồn : http://diendan.congdongcviet.com/threads/t36221::ban-chat-cua-viec-cap-phat-bo-nho-dong-giai-phong-bo-nho.cpp        bài viết khá hay nên minh copy qua đây




1. Dẫn nhập
Bộ nhớ là 1 tài nguyên quan trọng trong hệ thống , được phân phối điều phối phức tạp.

ở đây, chúng ta sẽ xét tương quan như sau cho dễ hiểu : đất là 1 tài nguyên quý giá trong thành phố và được điều phối bởi sở tài nguyên môi trường
(coi như thế, giờ hình như nó thuộc sở nhà đất thì phải,nói tóm lại là 
sở quản lí)


2. Cấp phát bộ nhớ :
Bộ nhớ quan trọng như thế ko thể tùy tiện sử dụng , vì trong máy có nhiều tiếng trình cần bộ nhớ, tùy tiện sử dụng thì lấy đâu ra mà dùng ????

ai cũng cần có đất, cứ tùy tiện lấy gì cần gì sở quản lý, như thế sẽ có người không có đất mà dùng ???



Cấp phát bộ nhớ hoạt động như thế nào : bản chất là trao quyền sử dụng.

hôm nay 1 người (1 con trỏ) xin cấp phát (malloc, new) 1 vùng đất, anh ta được trao quyền sử dụng 1 vùng đất đó. 
Khi này :
Có thể trên mảnh đất này đang trống rỗng (toàn null) nhưng cũng có thể trên đó đầy cỏ rác,hoa màu hoặc nhà cửa do người trước đó sử dụng vẫn còn . (điều này đối với anh ta mà nói nó hoàn toàn là ngẫu nhiên, ko ai có thể khẳng định được cả)
>>>>> khi ta xin cấp phát xong thì vùng nhớ đó hoàn toàn có giá trị ngẫu nhiên


Nếu như khi anh ta xin cấp phát mà có đút lót để ra thêm điều kiện hoặc trước đó anh ta có thuê thêm 1 người quét dọn xây sửa thì anh sẽ có được 1 mảnh đất có sẵn cái anh ta muốn
>>>> khi ta cấp phát đi cùng với ép buộc sẽ được vùng nhớ có giá trị như ta mong muốn
ví dụ 
PHP Code:
int *a=new int(4);int *b=(int*)malloc(1000);memset(b.....);
static 
int x[1000];
static 
int y[10]={1,2,3,4,5,6};  
<<<<<<<< toàn bộ điều này là đáp án tại sao khi cấp phát bộ nhớ lại có giá trị ngẫu nhiên



3. Giải phóng bộ nhớ như thế nào

Anh ta dùng xong đất rồi, ko cần nữa, đem trả quyền sử dụng mảnh đất lại cho khổ chủ.

Giải bộ nhớ hoạt động như thế nào : bản chất là trả lại quyền sử dụng
khi này :
sở sẽ thu lại quyền sử dụng đất của anh, thế là đủ rồi, sở ko cần phải động chạm sửa chữa lại gì vùng đất đó. Nên khi đó dù vùng đất đó đã được giải phóng nhưng mà hoa màu của a ta trên đó thì vẫn còn, ko có biến mất được

điều này giải thích tại sao khi mà trong 1 số hệ điều hành đời cổ, (các bạn lính mới bây giờ chắc không gặp) nhiều bạn thử giải phóng bộ nhớ rồi, delete rồi, free rồi mà khi in thử ra vẫn thấy kết quả như thế .
đơn giản thôi, a ta trả lại mảnh đất đó, nhưng chưa có ai thuê nó cả, chưa có ai sử dụng nên hôm sau ra xem thử thì nó vẫn như hôm trước khi a ta trả lại 
Các bạn đọc rõ chú ý ở dưới rồi hẵng hỏi thêm về câu này nhé.

Và các bạn phải chú ý là quyền sử dụng đất mới là cái được quan tâm duy nhất của vấn đề này

PHP Code:
int *a=new int[10];int *b=(int*)malloc(1000);  
thì giá trị trong a và b là địa chỉ của vùng nhớ được cấp phát. địa chỉ này sẽ được lưu lại trong sởsở sẽ dùng cái số địa chỉ này để hiểu là quyền sử dụng đất khi giải phóng

tiếp theo
PHP Code:
free(b);delete []a;  
2 câu lệnh này ko có làm thay đổi giá trị của a và ba và b vẫn trỏ vào mảnh đất đấy. ok ? Và càng ko can thiệp vào vùng nhớ mà a ,b trỏ đến, cái duy nhất mà nó làm là xác nhận vùng nhớ đó đã được trả lại, đang rảnh rỗi, có thể cho thuê tiếp.

<<< điều này giải thích cho cách hiểu sai lầm của 1 số bạn mới học đối với việc cấp phát và giải phóng



4. Memory leak

Câu hỏi mở rộng :
như thế này có phải là giải phóng ko
PHP Code:
    int*x=new int[20];
    
x=NULL;  <<<<< như thế này có phải là giải phóng ko  
ở trong C (not java, java khác) thì :
câu trả lời là không , bạn đã hiểu sai lầm hoàn toàn về việc giải phóng rồi, bạn nên đọc kĩ lại phần giải phóng để hiểu tại sao. 
như thế này chính là :
anh ta đánh mất cái quyền sử dụng đất của mình, kết quả là vùng đất đó ko được sở lấy về, sau nhiều lần như thế thì tài nguyên đất của sở càng ngày càng ít đi, hiện tượng này gọi mà memory leak


Sau khi chương trình kết thúc , việc bộ nhớ xin cấp phát có được tự giải phóng hay ko thì tùy thuộc vào cài đặt của trình biên dịch và hệ điều hành. Chúng ta có 2 khả năng 
· Khả năng 1 : trong phần khởi động (trước khi vào function main() ), program xin một khối memory cuả system gọi là XXXX và mỗi lần malloc được gọi thì cấp pháp một phần memory cuả XXXX cho malloc. Do đó, khi program exit thì trả XXXX về cho system là xong. Trong trường hợp này không bị mất memory
· Khả năng 2 : mỗi lần malloc được gọi thì xin memory từ system . Trường hợp này có thể memory không trả về cho system. Lúc này chương trình sẽ bị gọi là có memory leak.Như vậy sau vài lần chạy sẽ ko còn memory để cấp phát nữa


Đó là giải thích tại sao có nhiều chương trình chạy xong, thoát ra rồi, f5 mấy lần rồi mà máy vẫn cứ ì ì ì ra..........


5. Trên đây là cách lý thuyết cơ bản dành cho các bạn mới học, nó được áp dụng đối với lập trình trên console, (cấp sở tài nguyên thôi)
trong windows nó cũng như thế thôi nhưng mà nó có thêm nhiều quy tắc rằng buộc chặt chẽ hơn rất nhiều (cấp bộ tài nguyên và môi trường, phải khác chứ)

Muốn biết thêm về bộ nhớ thì xem chap 1 của tut dưới đây : 
 Portable Executable File Format




Update 9/9/10
Câu hỏi
Nhân tiện cho em hỏi, nếu mình khai báo 1 mảng có thể có rất nhiều phần tử thì bộ nhớ của nó sẽ được lấy từ đâu ra (Ổ cứng, Ram.... Hay là một cái gì đó mà em không biết :P). Khi em khai báo 1 mảng int a[1000000] thì nó báo là "Array size too large". Mới có 1000000 phần tử nó đã coi là lớn thì những bài toán thực tế vài triệu phần tử liền thì phải làm thế nào? hix
Trả lời
int a[1000000] ; khai báo ở đâu ?
em khai báo ở sở (tức là khai báo dạng local, trong các hàm )thì sở nó xin vùng nhớ ở stack segment, mà stack segment thì đây (trong ảnh, nhỏ gọn thế này, liệu nó có cho em vùng lớn thế kia ko 1000000*4byte)
 Click vào ảnh để xem hình đẩy đủ


đối với các bài toán cần nhiều vùng nhớ 1 cách kinh khủng thì ta thường dùng các hàm api về malloc để lấy các vùng nhớ ở free store được bộ (os-hệ điều hành) cấp phát, 

và 1 điều ko kém phần quan trọng đó là ta nên xây dựng những giải thuật thật thông minh chứ ko phải là load tràn hết lên bộ nhớ
ví dụ xây dựng trước các phương pháp xử lý các sự kiện có thể xảy ra 
giả sử như này, tôi có 1 khối thông tin, để bắt sự kiện "tìm nhân viên mới vào công ti", tôi lập ra 1 temponary, mỗi khi chèn thằng mới vào khối thông tin của tôi, tôi gán thằng temponary này bằng với nhân viên mới, như thế tôi đã có 1 phương pháp sử lí sự kiện tốt rồi đúng ko ???


Update 10/9/10
câu hỏi

Cấp phát động thì nó lấy bộ nhớ từ đâu vậy cà.
"data segment"
Là cái gì thế em dịch là dữ liệu phân đoạn, nghĩa là sao đây, anh langman bận rộn thế :P:P

a. theo giáo trình đại học FPT về OS,theo giáo trình thầy phạm văn ất về tổ thức bộ nhớ, khi tiến trình chạy , bộ nhớ được mô hình thành 4 phần như sau 


(trên thực tế, trong windows, môi trường ảo hóa cụ thể này thì có cách tổ chức phức tạp hơn phát triển từ lý thuyết này)
b. đang bận ôn thi ko có time online được


Update 20/11/10
Câu hỏi của quyết 1991 : sự khác nhau giữa malloc và new?


new và malloc khác nhau cực cực kì nhiều đó các pạn à
sơ bộ như sau, chưa phân tích kĩ
malloc là hàm, cấp phát trả về kiểu void *, malloc thì ko gọi hàm tạo
free ko gọi hàm hủy
malloc trả về NULL nếu thất bại

new là toán tử, new gọi hàm tạo, new có thể được đa năng hóa (nạp chồng), 
new ném ra exception nếu thất bại
toán tử new và toán tử new[] ko có khả năng realloc



Update tiếp câu hỏi hay 2/3/2010
Trích dẫn Nguyên bản được gửi bởi first_pace Xem bài viết
Anh cho em hỏi rõ hơn về đoạn này. Khi giải phóng rồi mà a và b vẫn trỏ đến mảnh đất đó thì nghĩa là nó vẫn có quyền kiểm soát khu vực đó, như vậy thì sao biết là khi đó đất là available đựoc ạ. Em có test một đoạn chương trình như sau.
C Code:
  1. #include <iostream>
  2. using namespace std;
  3.  
  4. int main(){
  5.     int *p;
  6.    
  7.     p= new int[2]; // xin chính quyền cấp hai khu đất
  8.     p[0]=8888; // khu này trồng rau
  9.     p[1]=9999; // khu này nuôi lợn
  10.     cout << p[0] << "  " << p[1] << endl; // xem tình hình ruộng rau và chuồng lợn
  11.    
  12.     delete [] p; // trả lại đất cho chính quyền
  13.     cout << p[0] << "  " << p[1] << endl; // xem chính quyền làm gì với ruộng rau và chuồng lợn
  14.    
  15.     system("pause");
  16.     return 0;
  17. }
kết quả là em không thấy ruộng rau và chuồng lợn đâu nữa  


em nghĩ có hai nguyên nhân
  • Thứ nhất: chính quyền đã làm gì đó với ruộng rau và chuông lợn của em (sửa đổi nội dung của vùng nhớ mà trước đó p trỏ tới, thay đổi 8888 và 9999) nhưng như anh nói nó không can thiệp vào.
  • Thứ hai: em nhìn nhầm sang một khu đất khác chứ không phải khu đất lúc trước nữa. Nhưng anh nói sau khi bị tứoc đoạt quyền sử dụng đất thì em vẫn nhìn vào khu đất đó (p vẫn trỏ tới vùng nhớ mà trước đó nó trỏ tới)

Nếu thế thì em không giải thích được kết quả của chương trình trên. Anh giải thích kỹ hơn giùm em với. Cám ơn anh 

xin khẳng định lại 1 lần nữa, e đã hiểu hoàn toàn sai lầm, FREE và DEL ko bao giờ thay đổi giá trị của con trỏ, hãy phân việt rõ ràng giữa giá trị của con trỏ và giá trị nó trỏ đến

free nó là void free(void *mem) vậy thì xin hỏi con trỏ mem làm sao có thể thay đổi giá trị qua hàm này (xin hãy đọc bài bản chất con trỏ trong C để hiểu sâu hơn vấn đề này, tip : phân biệt rõ ràng giữa giá trị của mem và giá trị của thằng mà mem trỏ tới)


check lại đoạn code sau đây

C++ Code:
  1. #include <iostream>
  2. using namespace std;
  3.  
  4. int main(){
  5.     int *p;
  6.  
  7.     p= new int[2]; // xin chính quyền cấp hai khu đất
  8.     p[0]=8888; // khu này trồng rau
  9.     p[1]=9999; // khu này nuôi lợn
  10.     cout << p[0] << "  " << p[1] << endl; // giá trị trỏ đến
  11.     printf("%x\n",p);     // giá trị của p <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  12.    
  13.  
  14.     delete [] p; // trả lại đất cho chính quyền
  15.     cout << p[0] << "  " << p[1] << endl; // xem chính quyền làm gì với ruộng rau và chuồng lợn
  16.     printf("%x\n",p); // giá trị của p  <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  17.  
  18.     system("pause");
  19.     return 0;
  20. }



điều nữa
Giải bộ nhớ hoạt động như thế nào : bản chất là trả lại quyền sử dụng
khi này :
sở sẽ thu lại quyền sử dụng đất của anh, thế là đủ rồi, sở ko cần phải động chạm sửa chữa lại gì vùng đất đó. Nên khi đó dù vùng đất đó đã được giải phóng nhưng mà hoa màu của a ta trên đó thì vẫn còn, ko có biến mất được

điều này giải thích tại sao khi mà nhiều bạn thử giải phóng bộ nhớ rồi, delete rồi, free rồi mà khi in thử ra vẫn thấy kết quả như thế .
đơn giản thôi, a ta trả lại mảnh đất đó, nhưng chưa có ai thuê nó cả, chưa có ai sử dụng nên hôm sau ra xem thử thì nó vẫn như hôm trước khi a ta trả lại
giả sử ngay khi em vừa trả , có thằng khác nó đến thuê luôn thì lập tức nó bỏ hoa màu của em đi, trồng hoa màu khác thì em quay lại làm gì còn thời đại này nhanh như ăn cắp ý mà

(windows có bao nhiêu process, thread,? nên việc bị thuê ngay lập tức là quá bình thường, em à, đặc biệt nếu là hàng nằm trên stack thì thay đổi liên tục là bt)


More :
Trích dẫn Nguyên bản được gửi bởi first_pace Xem bài viết
Thanks anh, giá trị của con trỏ và giá trị của vùng nhớ mà con trỏ trỏ tới thì em biết. Em chỉ thắc mắc không hiểu tại sao khi kiểm tra lại thì giá trị của vùng nhớ lại bị thay đổi (8888 và 9999) nên em với đặt ra hai khả năng:
  • Thứ nhất: chính quyền đã làm gì đó với ruộng rau và chuông lợn của em (sửa đổi nội dung của vùng nhớ mà trước đó p trỏ tới, thay đổi 8888 và 9999) nhưng như anh nói nó không can thiệp vào.
  • Thứ hai: em nhìn nhầm sang một khu đất khác chứ không phải khu đất lúc trước nữa. Nhưng anh nói sau khi bị tứoc đoạt quyền sử dụng đất thì em vẫn nhìn vào khu đất đó (p vẫn trỏ tới vùng nhớ mà trước đó nó trỏ tới)

Và theo câu trả lời của anh nó là khả năng thứ nhất, bị thằng nào đó thuê lại ngay sau đó:

Thanks anh đã giải đáp đoạn này, em không biết là nó lại bị thuê luôn như thế, em hiểu rồi 
khi em cài hook bắt các API trên window sẽ thấy LocalAlloc, RemoteAlloc,GlobalAlloc... được xài rất nhiều lần trên /1s chứ ko phải (ví dụ nhỏ xem ở hình dưới , đó là chỉ trong 1 tiến trình firefox thôi đó, chứ ko phải xét trên 5x process đang chạy)


tuy nhiên đối với các môi trường cũ, đặc biệt như trên borland C for dos thì hiện tượng free rồi mà còn tài nguyên rất hay xảy ra, có rât rất nhiều người hiểu lầm là lỗi, rồi ... (đã có rất nhiều câu hỏi như thế trong box thắc mắc C). đó là lý do vì sau a phải nhấn mạnh điều đó

Không có nhận xét nào:

Đăng nhận xét