2009-05-14 35 views
6

Tôi đã viết một chương trình C trong Linux mà bộ nhớ mallocs, chạy nó trong một vòng lặp, và TOP không hiển thị bất kỳ mức tiêu thụ bộ nhớ nào.Có một số người phân bổ lười biếng không?

sau đó tôi đã làm điều gì đó với bộ nhớ đó và TOP đã hiển thị mức tiêu thụ bộ nhớ.

Khi tôi malloc, tôi thực sự "có được bộ nhớ", hoặc là có một "lười biếng" bộ nhớ quản lý, mà chỉ mang lại cho tôi bộ nhớ nếu/khi tôi sử dụng nó?

(Ngoài ra còn có một tùy chọn TOP chỉ biết về tiêu thụ bộ nhớ khi tôi sử dụng nó, vì vậy tôi không chắc chắn về điều này ..)

Cảm ơn

Trả lời

15

Trên Linux, malloc yêu cầu bộ nhớ với sbrk() hoặc mmap() - một trong hai cách, không gian địa chỉ của bạn được mở rộng ngay lập tức, nhưng Linux không chỉ định các trang thực của bộ nhớ vật lý cho đến khi ghi đầu tiên vào trang được đề cập. Bạn có thể thấy việc mở rộng vùng địa chỉ trong cột VIRT, trong khi sử dụng bộ nhớ vật lý thực tế trong RES.

+0

có giống với cửa sổ không? – TStamper

+0

Tôi không quen với những gì Windows làm, xin lỗi. – bdonlan

+0

bdonlan: Đúng, nhưng anh ta nên chú ý đến hiệu ứng của ngã ba "* Đứa trẻ không thừa kế bộ nhớ của cha mẹ nó (mlock (2), mlockall (2)). " khi anh ấy nhìn vào đầu trang – RandomNickName42

3

Có, bộ nhớ không được ánh xạ vào bộ nhớ của bạn trừ khi bạn chạm vào nó. bộ nhớ mallocing sẽ chỉ thiết lập các bảng phân trang để chúng biết khi bạn nhận được một pagefault trong bộ nhớ được cấp phát, bộ nhớ sẽ được ánh xạ.

0

Bạn có sử dụng tối ưu hóa trình biên dịch không? Có lẽ trình tối ưu hóa đã xóa phân bổ vì bạn không sử dụng tài nguyên được phân bổ?

+0

Cảm ơn Ryan, tôi đã xem xét nhị phân có bộ tách rời và cuộc gọi 'malloc' đã ở đó. –

+0

+1 để chống lại các phiếu bầu tiêu cực. Đây là câu trả lời hay cho câu hỏi. –

+1

Trình biên dịch không thể xóa một hàm mà không có triển khai hiển thị hoặc một hàm có thể có các tác dụng phụ. – BeeOnRope

3

Điều này bắt đầu một chút tắt chủ đề (và sau đó tôi sẽ tie nó vào câu hỏi của bạn), nhưng những gì đang xảy ra tương tự như những gì sẽ xảy ra khi bạn ngã ba một quá trình trong Linux. Khi forking có một cơ chế được gọi là copy on write, nó chỉ sao chép không gian bộ nhớ cho quá trình mới khi bộ nhớ được ghi. Bằng cách này, nếu quá trình chia rẽ thực thi một chương trình mới ngay lập tức thì bạn đã tiết kiệm được chi phí cho việc sao chép bộ nhớ chương trình gốc.

Quay lại câu hỏi của bạn, ý tưởng tương tự. Như những người khác đã chỉ ra, yêu cầu bộ nhớ đưa cho bạn không gian bộ nhớ ảo ngay lập tức, nhưng các trang thực tế chỉ được phân bổ khi viết cho chúng.

Mục đích của việc này là gì? Về cơ bản nó làm cho bộ nhớ mallocing hoạt động thời gian không đổi hoặc liên tục Big O (1) thay vì một hoạt động Big O (n) (tương tự như cách mà bộ lập lịch linux lan truyền nó thay vì làm nó trong một đoạn lớn).

Để chứng minh những gì tôi có nghĩa là tôi đã làm thí nghiệm sau:

[email protected]:~/test_code$ time ./bigmalloc 

real 0m0.005s 
user 0m0.000s 
sys 0m0.004s 
[email protected]:~/test_code$ time ./deadbeef 

real 0m0.558s 
user 0m0.000s 
sys 0m0.492s 
[email protected]:~/test_code$ time ./justwrites 

real 0m0.006s 
user 0m0.000s 
sys 0m0.008s 

Chương trình bigmalloc phân bổ 20 triệu ints, nhưng không làm bất cứ điều gì với họ. deadbeef viết một int cho mỗi trang kết quả trong 19531 viết và ghi đè phân bổ 19531 ints và số không chúng ra. Như bạn có thể thấy deadbeef mất khoảng 100 lần lâu hơn để thực hiện hơn bigmalloc và khoảng 50 lần dài hơn so với chữ viết tay.

#include <stdlib.h>  

int main(int argc, char **argv) { 

int *big = malloc(sizeof(int)*20000000); // allocate 80 million bytes 

return 0; 

} 

.

#include <stdlib.h>  

int main(int argc, char **argv) { 

int *big = malloc(sizeof(int)*20000000); // allocate 80 million bytes 

// immediately write to each page to simulate all at once allocation 

// assuming 4k page size on 32bit machine 

for (int* end = big + 20000000; big < end; big+=1024) *big = 0xDEADBEEF ;  

return 0; 

} 

.

#include <stdlib.h> 

int main(int argc, char **argv) { 

int *big = calloc(sizeof(int),19531); // number of writes 

return 0; 
} 
+0

Câu trả lời hay, cảm ơn! (Khá ngạc nhiên khi biết rằng 0xDEADBEAF là thuật ngữ đã biết http://en.wikipedia.org/wiki/Hexspeak) –

0

Tính năng này được gọi là overcommit - hạt nhân "hứa ​​hẹn" bạn nhớ bằng cách tăng kích thước phân đoạn dữ liệu, nhưng không phân bổ bộ nhớ vật lý với nó.Khi bạn chạm vào một địa chỉ trong không gian mới đó, trang quy trình sẽ đưa vào hạt nhân, sau đó cố gắng ánh xạ các trang vật lý vào đó.

0

Có, lưu ý các VirtualAlloc cờ,

MEM_RESERVE 
MEM_COMMIT 

.

Heh, nhưng đối với Linux hoặc hệ thống bất kỳ POSIX/BSD/SVR#, vfork(), đã có tuổi và cung cấp chức năng mô phỏng.

Các vfork() chức năng khác với fork() chỉ trong quá trình đứa trẻ có thể chia sẻ mã và dữ liệu với các quá trình gọi (quá trình cha mẹ). Điều này tốc độ nhân bản hoạt động đáng kể có nguy cơ về tính toàn vẹn của quy trình cha mẹ nếu vfork() bị lạm dụng.

Việc sử dụng vfork() cho bất kỳ mục đích trừ như một khúc dạo đầu cho một gọi ngay đến một chức năng từ gia đình exec , hoặc để _exit(), không được khuyến cáo.

Chức năng vfork() có thể được sử dụng để tạo quy trình mới mà không cần hoàn toàn sao chép không gian địa chỉ của quy trình cũ. Nếu quá trình chia hai chỉ đơn giản là sẽ thực hiện lệnh gọi, không gian dữ liệu được sao chép từ cha mẹ sang con bằng fork() không được sử dụng. Đây là đặc biệt không hiệu quả trong môi trường được phân trang, làm cho vfork() đặc biệt hữu ích. Tùy thuộc vào kích thước không gian dữ liệu của cha mẹ, vfork() có thể cung cấp một cải thiện hiệu suất đáng kể trên ngã ba().

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