1. Trang chủ
  2. » Luận Văn - Báo Cáo

bài tập lớn đề tài quản lý bộ nhớ

15 0 0
Tài liệu đã được kiểm tra trùng lặp

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Nội dung

Sau khi biên dịch, các lệnh và hầu hết các dữ liệu đều đã có địa chỉ xác định.Khích thước tối đa của không gian địa chỉ không phụ thuộc vào việc bao nhiêu bộ nhớ RAM vật lý thực sự có th

Trang 1

TRƯỜNG ĐẠI HỌC PHENIKAA KHOA KHOA HỌC CƠ BẢN

MỞ ĐẦU

Trang 2

Bộ nhớ chính là thiết bị lưu trữ duy nhất thông qua đó CPU có thể trao đổi thông tin với môi trường ngoài, do vậy nhu cầu tổ chức, quản lý bộ nhớ là một trong những nhiệm vụ trọng tâm hàng đầu của hệ điều hành Bộ nhớ chính được tổ chức như một mảng một chiều các từ nhớ (word), mỗi từ nhớ có một địa chỉ VIệc trao đổi thông tin với môi trường ngoài được thực hiện thồn qua các thao tác đọc hoặc ghi dữ liệu vào một địa chỉ cụ thể nào đó trong bộ nhớ.

Hầu hết các hệ điều hành hiện đại đều cho phép chế độ đa nhiệm nhằm nâng cao hiệu suất của CPU Tuy nhiên kỹ thuật này lại làm nảy sinh nhu cầu chia sẻ bộ nhớ giữa các tiến trình khác nhau Và bài viết này sẽ cho bạn thêm kiến thức trìu tượng về không gian bộ nhớ, bộ nhớ api và cách các tiến trình làm việc với bộ nhớ thông qua cơ chế dịch địa chỉ.

NỘI DUNG

Trang 3

1.Address Spaces

-Không gian địa chỉ (memory address space) là gì? Đó là dải các số được dùngđể đánh địa chỉ cho các lệnh, hoặc dữ liệu của chương trình Sau khi biên dịch, các lệnh và hầu hết các dữ liệu đều đã có địa chỉ xác định.

Khích thước tối đa của không gian địa chỉ không phụ thuộc vào việc bao nhiêu bộ nhớ RAM vật lý thực sự có thể sử dụng được, do đó nó được biết đến là không gian địa chỉ ảo (virtual address space) Một lý do khác cho thuật ngữ này, mỗi process có suy nghĩ rằng chúng chỉ sống trong vùng địa chỉ này và không hề tồn tạicác process khác từ quan điểm của chúng ứng dụng không cần quan tâm đến các ứng dụng khác và có thể hoạt động như thể chúng là quá trình duy nhất, điều này không đúng với thực tế nên nó được gọi là không gian địa chỉ ảo.

Linux chia virtual address space thành 2 phần: kernel space và userspace.Mỗi user process trong hệ thống sở hữu bộ nhớ có kích thước từ 0 -> TASK_SIZE.Phần địa chỉ từ TASK_SIZE -> 264/232 được dành cho kernel và không thể bị truycập từ user process TASK_SIZE là một hằng số kiến trúc mà nó dùng để chia tỷ lệkhông gian bộ nhớ Ví dụ trong IA-32(32 bit), không gian địa chỉ được chia ra 3GiB cho mỗi process và 1GiB còn lại dành cho kernel (232 = 4GiB) Note: 210 = 1KiB, 220 = 1Mib, 230 = 1Gib.

Cách chia này không phụ thuộc vào việc có bao nhiêu bộ nhớ RAM có thể sử dụng Vì có sự ảo hóa nên mỗi user process nghĩ rằng nó có 3GiB bộ nhớ Các userspace của các process thực sự tách biệt với nhau nhưng kernel space ở vùng trên cùng của không gian địa chỉ ảo thì luôn giống nhau.

-hiện nay, đa số các hệ điều hành sử dụng cơ chế virtual memory để quản lý bộ nhớ.Nhưng vẫn còn một số hệ điều hành không dùng virtual memory, ví dụ uCLinux.

2.Địa chỉ ảo(virtual address space)

Trang 4

Khống như hầu hết các kernel hiện đại, Linux sử dụng 1 kỹ thuật được gọi là quản lý bộ nhớ ảo (virtual memory management) nhằm mục đích sử dụng hiệu quả cả CPU và RAM (bộ nhớ vật lý hay, cũng có thể được gọi là bộ nhớ thật) Kỹ thuật này khai thác 1 đặc điểm chung về truy cập bộ nhớ của hầu hết các chương trình là locality of reference (dịch nôm na là tham chiếu vùng), được biểu hiện qua 2 đặc tính sau:

• Spatial locality: chương trình có xu hướng tham chiếu đến địa chỉ bộ nhớ gần với phân vùng bộ nhớ mà nó đang truy cập Vì chương trình C xử lý các chỉ lệnh một cách tuần tự, hoặc chương trình xử lý các struct (vùng nhớ của các thành phần của struct được sắp xếp liền kề nhau)

• Temporal locality: chương trình có xu hướng truy cập cùng 1 vùng nhớ trongcác thời điểm rất gần nhau Ví dụ trường hợp xử lý vòng lặp, các vùng nhớ có thể được truy cập nhiều lần các thời điểm gần nhau mỗi khi vòng lặp quay lại.Nhìn vào đăc tính locality of reference này, chúng ta có thể rút ra là 1 chương trình có thể chạy được khi chỉ cần 1 phần không gian địa chỉ của nó trên RAM, thay vì tải toàn bộ không gian bộ nhớ của tiến trình.

Một bộ nhớ ảo chia không gian bộ nhớ của 1 tiến trình ra làm nhiều đoạn nhỏ có kích thước cố định được gọi là các trang (page) Tương tự, RAM cũng được chia làm nhiều đoạn nhỏ cùng kích thước được gọi là page frame Trong 1 thời điểm, chỉ 1 vài trang của tiến trình cần có mặt trong các frame của RAM để chạy Các trang chưa được sử dụng của chương trình sẽ được để trong phân vùng swap (là phân vùng dự trữ của ổ cứng hỗ trợ lưu trũ bổ sung cho RAM) và sẽ được tải vào RAM khi cần thiết.

Page table

Để ánh xạ giữa các trang của không gian bộ nhớ ảo đến các frame của bộ nhớ vật lý, kernel tạo ra 1 bảng trang (page table) cho mỗi tiến trình Mỗi entry của page table ứng với 1 trang của bộ nhớ ảo cho phép chỉ ra vị trí của trang đó trong RAM hoặc chỉ ra nó đang nằm ở phân vùng swap của ổ cứng.

Để hình dung rõ hơn về page table, chúng ta xem hình dưới đây:

Hình 1: Page Table của một tiến trình

Trang 5

Trong thực tế, không cần phải xây dựng bảng ánh xạ cho tất cả không gian địa chỉ bộ nhớ ảo của tiến trình Trái lại, thường chỉ có 1 phần số lượng các trang trong số đó được sử dụng và cần phải có bảng ánh xạ cho các trang đó Vì vậy, về mặt lý thuyết không cần phải xây dựng entry cho toàn bộ không gian bộ nhớ ảo của tiến trình.

3.Multiprogramming and Time Sharing.

3.1Hệ thống đa chương trinh( multiprogram) là gì?

Đa chương trình là sự chuyển đổi nhanh chóng của CPU giữa một số chương trình.Một chương trình thường được tạo thành từ một số nhiệm vụ Một tác vụ thường kết thúc với một số yêu cầu di chuyển dữ liệu sẽ yêu cầu một số hoạt động I / O được thực hiện Đa nhiệm thường được thực hiện để giữ cho CPU bận rộn, trong khi chương trình hiện đang chạy đang thực hiện các hoạt động I / O So với các lệnh thực thi khác, các thao tác I / O cực kỳ chậm Ngay cả khi một chương trình chứa một số lượng rất nhỏ các thao tác I / O, thì phần lớn thời gian dành cho chương trình được dành cho các hoạt động I / O đó Do đó, việc sử dụng thời gian nhàn rỗi này và cho phép một chương trình khác sử dụng CPU tại thời điểm đó sẽ làm tăng hiệu suất sử dụng CPU Đa chương trình ban đầu được phát triển vào cuốinhững năm 1950 như một tính năng của hệ điều hành và lần đầu tiên được sử dụng trong máy tính máy tính lớn Với sự ra đời của bộ nhớ ảo và công nghệ máy ảo, việc sử dụng đa chương trình đã được tăng cường.

3.2 Hệ thống chia sẻ thời gian là gì?

Chia sẻ thời gian, được giới thiệu vào năm 1960, là sự chia sẻ tài nguyên máy tính giữa một số người dùng cùng một lúc Trong hệ thống chia sẻ thời gian, một số thiết bị đầu cuối được gắn vào một máy chủ chuyên dụng duy nhất có CPU riêng của nó Các hành động / lệnh được thực thi bởi hệ điều hành của hệ thống chia sẻ thời gian có khoảng thời gian rất ngắn Do đó, CPU được chỉ định cho người dùng tại các thiết bị đầu cuối trong một khoảng thời gian ngắn, do đó người dùng trong thiết bị đầu cuối có cảm giác rằng cô ấy có một CPU dành riêng cho mình phía sau thiết bị đầu cuối của mình Khoảng thời gian ngắn mà một lệnh được thực hiện trênhệ thống chia sẻ thời gian được gọi là lát thời gian hoặc lượng tử thời gian Với sự phát triển của internet, các hệ thống chia sẻ thời gian đã trở nên phổ biến hơn vì các trang trại máy chủ đắt tiền có thể chứa một lượng lớn khách hàng chia sẻ cùng

Trang 6

một tài nguyên Vì các trang web hoạt động chủ yếu theo từng đợt hoạt động sau đó là khoảng thời gian không hoạt động, thời gian không hoạt động của một khách hàng có thể được sử dụng hiệu quả bởi khách hàng kia mà không ai trong số họ nhận thấy sự chậm trễ.

3.3Đa chương trình so với Hệ thống chia sẻ thời gian

Đa chương trình là phân bổ nhiều hơn một chương trình đồng thời trên một hệ thống máy tính và các tài nguyên của nó Đa chương trình cho phép sử dụng CPU một cách hiệu quả bằng cách cho phép nhiều người dùng khác nhau sử dụng CPU và các thiết bị I / O một cách hiệu quả Đa chương trình đảm bảo rằng CPU luôn cóthứ gì đó để thực thi, do đó làm tăng hiệu suất sử dụng CPU Mặt khác, Chia sẻ thời gian là việc chia sẻ tài nguyên máy tính giữa một số người dùng cùng một lúc.Vì điều này sẽ cho phép một số lượng lớn người dùng làm việc trong một hệ thống máy tính duy nhất cùng một lúc, nó sẽ giảm chi phí cung cấp khả năng tính toánIII.Interlude: API memory

1 Các loại bộ nhớ

Khi chạy chương trình C, có hai loại bộ nhớ được cấp phát Đầu tiên được gọi là bộ nhớ ngăn xếp, và các phân bổ và phân bổ của nó được quản lý ngầm bởi trìnhbiên dịch cho bạn, người lập trình; vì lý do này đôi khi nó được gọi là bộ nhớ tự động.

Khai báo bộ nhớ trên ngăn xếp trong C rất dễ dàng Ví dụ: giả sử bạn cần một số khoảng trống trong hàm func () cho một số nguyên, được gọi là x Để khai báo một phần bộ nhớ như vậy, bạn chỉ cần làm như sau:

Trang 7

Chính nhu cầu về bộ nhớ tồn tại lâu dài này đã đưa chúng ta đến loại bộ nhớ thứhai, được gọi là bộ nhớ heap, nơi tất cả các phân bổ và phân bổ được xử lý rõ ràng.Dưới đây là một ví dụ về cách người ta có thể phân bổ một số nguyên trên heap:void func () {

int * x = (int *) malloc (sizeof (int));

Do bản chất rõ ràng của nó và vì cách sử dụng đa dạng hơn, bộ nhớ heap đặt ra nhiều thách thức hơn cho cả người dùng và hệ thống.

2 The malloc () Call

Lệnh malloc () call khá đơn giản: bạn chuyển nó vào một kích thước yêu cầu một số phòng trên heap, và nó thành công và trả lại cho bạn một con trỏ đến khônggian mới được cấp phát, hoặc không thành công và trả về NULL

Trang hướng dẫn cho thấy những gì bạn cần làm để sử dụng malloc; gõ man malloc tại dòng lệnh và bạn sẽ thấy:

#include <stdlib.h>

void *malloc (size_t size);

Từ thông tin này, bạn có thể thấy rằng tất cả những gì bạn cần làm là bao gồm tệp tiêu đề stdlib.h để sử dụng malloc

Tham số đơn malloc () nhận có kiểu size_t, nó chỉ đơn giản mô tả bạn cần bao nhiêu byte Các quy trình và macro khác nhau được sử dụng Ví dụ: để phân bổ không gian cho giá trị dấu phẩy động có độ chính xác kép, bạn chỉ cần thực hiện như sau:

double * d = (double *) malloc (sizeof (double));3 The free () Call

Trang 8

Hóa ra, phân bổ bộ nhớ là một phần dễ dàng của phương trình; biết khi nào, bằng cách nào và thậm chí nếu để giải phóng bộ nhớ mới là phần khó Để giải phóng bộ nhớ heap không còn được sử dụng, lập trình viên chỉ cần gọi free ():int *x = malloc (10 * sizeof (int));

free (x);

Quy trình nhận một đối số, một con trỏ được trả về bởi malloc () Do đó, ta có thể nhận thấy, kích thước của vùng được cấp phát không được người dùng chuyển vào và phải được theo dõi bởi chính thư viện cấp phát bộ nhớ.

4 Các lỗi phổ biến Quên phân bổ bộ nhớ

Nhiều quy trình mong đợi bộ nhớ được cấp phát trước khi bạn gọi chúng Ví dụ:strcpy thường trình (dst, src) sao chép một chuỗi từ con trỏ nguồn sang con trỏ đích Tuy nhiên, nếu không cẩn thận, bạn có thể làm như sau:

char * src = "xin chào";char * dst;

char * dst = (char *) malloc (strlen (src)); // quá nhỏ!strcpy (dst, src); // hoạt động bình thường

Mặc dù nó chạy đúng một lần nhưng không có nghĩa là nó chính xác Vì nó có thể xảy ra nhiều trường hợp khác nhau như chương trình bị lỗi và sập, …

Trang 9

Quên khởi tạo bộ nhớ được phân bổ

Với lỗi này, bạn gọi malloc () đúng cách, nhưng quên điền một số giá trị vào kiểu dữ liệu mới được cấp phát của bạn Nếu bạn quên, chương trình sẽ gặp phải một lần đọc chưa được khởi tạo, nơi nó đọc từ đống dữ liệu có giá trị không xác định May mắn thì chương trình vẫn sẽ hoạt động còn không thì có thể sẽ có hại cho chương trình.

Quên để giải phóng bộ nhớ

Một lỗi phổ biến khác được gọi là rò rỉ bộ nhớ và nó xảy ra khi bạn quên giải phóng bộ nhớ Trong các ứng dụng hoặc hệ thống chạy lâu (chẳng hạn như chính hệ điều hành), đây là một vấn đề lớn, vì chậm việc tạo bộ nhớ cuối cùng dẫn đến việc hết bộ nhớ, tại thời điểm đó, khởi động lại là bắt buộc Vì vậy, nói chung, khi bạn sử dụng xong một phần bộ nhớ, bạn nên giải phóng nó.

Giải phóng bộ nhớ trước khi bạn hoàn tất

Đôi khi một chương trình sẽ giải phóng bộ nhớ trước khi nó được sử dụng xong; một lỗi như vậy được gọi là con trỏ treo lơ lửng, và nó, như bạn có thể đoán, cũng là một điều tồi tệ Việc sử dụng tiếp theo có thể làm hỏng chương trình hoặc ghi đè bộ nhớ hợp lệ (ví dụ: bạn đã gọi là free (), nhưng sau đó lại gọi là malloc () để cấp phát một thứ khác, sau đó sẽ tái chế bộ nhớ được giải phóng một cách sai lầm).

Giải phóng bộ nhớ lặp đi lặp lại

Các chương trình cũng đôi khi giải phóng bộ nhớ nhiều hơn một lần; cái này được gọi là miễn phí gấp đôi Kết quả của việc làm như vậy là không xác định Như bạn có thể tưởng tượng, thư viện cấp phát bộ nhớ có thể bị nhầm lẫn và làm đủ thứ chuyện kỳ lạ; sự cố là một kết quả phổ biến.

Calling free () không chính xác

Một vấn đề cuối cùng mà chúng ta thảo luận là việc gọi free () không chính xác.Rốt cuộc, free () mong rằng bạn chỉ chuyển tới nó một trong những con trỏ mà bạn đã nhận được từ malloc () trước đó Khi bạn vượt qua một số giá trị khác, những điều tồi tệ có thể xảy ra Vì vậy, những giải phóng không hợp lệ như vậy rất nguy hiểm và tất nhiên cũng nên tránh.

5 Các lệnh Call khác

Trang 10

Có một số lệnh gọi khác mà thư viện cấp phát bộ nhớ hỗ trợ Ví dụ, calloc () cấp phát bộ nhớ và cũng làm cho nó bằng không trước khi trả về; điều này ngăn ngừa một số lỗi trong đó bạn cho rằng bộ nhớ bị xóa và quên tự khởi tạo bộ nhớ đó(xem đoạn văn về “các lần đọc chưa được khởi tạo” ở trên) Quy trình realloc () cũng có thể hữu ích, khi bạn đã cấp phát không gian cho một thứ gì đó (ví dụ, một mảng), và sau đó cần thêm thứ gì đó vào nó: realloc () tạo một vùng bộ nhớ mới lớn hơn, sao chép vùng cũ vào nó và trả lại con trỏ đến vùng mới.

III Dịch địa chỉ 1.Khái niệm

Một trong những hướng tiếp cận trung tâm nhằm tổ chức quản lý bộ nhớ một cách hiệu quả là đưa ra không gian địa chỉ được xây dựng trên không gian nhớ vật lí quacơ chế dịch địa chỉ.

Với dịch địa chỉ, phần cứng sẽ biến đổi từng lần truy cập bộ nhớ (ví dụ: tìm nạp, tải hoặc lưu trữ lệnh), thay đổi địa chỉ ảo do lệnh cung cấp thành địa chỉ vật lý nơi thực sự có thông tin mong muốn Do đó, trên mỗi và mọi tham chiếu bộ nhớ, một bản dịch địa chỉ được phần cứng thực hiện để chuyển hướng các tham chiếu bộ nhớ ứng dụng đến vị trí thực tế của chúng trong bộ nhớ

Tất nhiên, phần cứng một mình không thể ảo hóa bộ nhớ, vì nó chỉ cung cấp cơ chếcấp thấp để thực hiện việc đó một cách hiệu quả Hệ điều hành phải tham gia vào các điểm chính để thiết lập phần cứng sao cho các bản dịch chính xác diễn ra; do đó, nó phải quản lý bộ nhớ, theo dõi vị trí nào trống và vị trí nào đang được sử dụng, đồng thời can thiệp một cách thận trọng để duy trì quyền kiểm soát cách sử dụng bộ nhớ.

Ví dụ: Một chuỗi mã ngắn tải một giá trị từ bộ nhớ, tang giá trị đó lên 3 lần rồi lưu lại giá trị đó trở lại bộ nhớ (theo ngôn ngữ C).

void func() { int x = 3000;Perry x = x + 3; …

Trang 11

Trình biên dịch biến dòng mã này thành hợp ngữ, trông có vẻ một cái gì đó như thếnày (trong cụm x86) Sử dụng objdump trên Linux hoặc otool trên máy Mac để tháo rời nó:

128: movl 0x0(%ebx), %eax ;load 0+ebx into eax 132: addl $0x03, %eax ;add 3 to eax register 135: movl %eax, 0x0(%ebx) ;store eax back to mem

Đoạn mã này tương đối đơn giản; nó cho rằng địa chỉ của x đã được đặt trong thanh ghi ebx, sau đó tải giá trị tại địa chỉ đó vào thanh ghi mục đích chung eax bằng cách sử dụng lệnh movl (đối với di chuyển “từ dài”) Lệnh tiếp theo thêm 3 vào eax và lệnh cuối cùng lưu giá trị trong eax trở lại bộ nhớ tại đó cùng một vị trí.

Hình 3.1

Ngày đăng: 24/07/2024, 16:14

TÀI LIỆU CÙNG NGƯỜI DÙNG

TÀI LIỆU LIÊN QUAN

w