Đang tải thư viện dùng chung và sử dụng RAM


40

Tôi đang tự hỏi về cách Linux quản lý các thư viện chia sẻ. (thực ra tôi đang nói về Maemo Fremantle, một bản phân phối dựa trên Debian được phát hành năm 2009 chạy trên RAM 256 MB).

Giả sử chúng ta có hai tệp thực thi liên kết đến libQtCore.so.4 và sử dụng các ký hiệu của nó (sử dụng các lớp và hàm của nó). Để đơn giản, hãy gọi cho họ ab. Chúng tôi giả định rằng cả hai thực thi liên kết đến cùng một thư viện.

Đầu tiên chúng tôi ra mắt a. Thư viện phải được tải. Nó được tải toàn bộ hay chỉ được tải vào bộ nhớ trong phần bắt buộc (vì chúng tôi không sử dụng mỗi lớp, chỉ có mã liên quan đến các lớp đã sử dụng đang được tải)?

Sau đó chúng tôi ra mắt b. Chúng tôi cho rằng avẫn đang chạy. bcũng liên kết đến libQtCore.so.4 và sử dụng một số lớp asử dụng, nhưng cũng có một số lớp không được sử dụng a. Thư viện sẽ được tải gấp đôi (riêng cho avà riêng cho b)? Hoặc họ sẽ sử dụng cùng một đối tượng đã có trong RAM. Nếu bsử dụng không có ký hiệu mới và ađang chạy, RAM được sử dụng bởi các thư viện dùng chung có tăng không? (Hoặc sự khác biệt sẽ không đáng kể)

Câu trả lời:


53

LƯU Ý: Tôi sẽ giả định rằng máy của bạn có đơn vị ánh xạ bộ nhớ (MMU). Có một phiên bản Linux (GianClinux) không yêu cầu MMU và câu trả lời này không áp dụng ở đó.

MMU là gì? Đó là phần cứng của bộ xử lý và / hoặc bộ điều khiển bộ nhớ. Hiểu liên kết thư viện dùng chung không yêu cầu bạn hiểu chính xác cách MMU hoạt động, chỉ là MMU cho phép có sự khác biệt giữa các địa chỉ bộ nhớ logic (các địa chỉ được sử dụng bởi các chương trình) và vật lýđịa chỉ bộ nhớ (những địa chỉ thực sự hiện diện trên bus bộ nhớ). Bộ nhớ được chia thành các trang, thường có kích thước 4K trên Linux. Với 4k trang, địa chỉ lôgic 0404095 là trang 0, địa chỉ lôgic 4096 Biệt8191 là trang 1, v.v. MMU ánh xạ chúng tới các trang vật lý của RAM và mỗi trang logic có thể được ánh xạ thành 0 hoặc 1 trang vật lý. Một trang vật lý nhất định có thể tương ứng với nhiều trang logic (đây là cách chia sẻ bộ nhớ: nhiều trang logic tương ứng với cùng một trang vật lý). Lưu ý điều này áp dụng bất kể hệ điều hành; đó là một mô tả về phần cứng.

Khi chuyển đổi quy trình, nhân thay đổi ánh xạ trang MMU, để mỗi quy trình có không gian riêng. Địa chỉ 4096 trong quy trình 1000 có thể (và thường là) hoàn toàn khác với địa chỉ 4096 trong quy trình 1001.

Khá nhiều bất cứ khi nào bạn nhìn thấy một địa chỉ, đó là một địa chỉ hợp lý. Các chương trình không gian người dùng hầu như không bao giờ xử lý các địa chỉ vật lý.

Bây giờ, có nhiều cách để xây dựng thư viện là tốt. Giả sử một chương trình gọi hàm foo()trong thư viện. CPU không biết gì về các ký hiệu, hoặc các hàm gọi thực sự, nó chỉ biết cách nhảy đến một địa chỉ logic và thực thi bất kỳ mã nào nó tìm thấy ở đó. Có một số cách nó có thể làm điều này (và những điều tương tự được áp dụng khi thư viện truy cập dữ liệu toàn cầu của chính nó, v.v.):

  1. Nó có thể mã cứng một số địa chỉ logic để gọi nó tại. Điều này đòi hỏi thư viện luôn được tải tại cùng một địa chỉ logic. Nếu hai thư viện yêu cầu cùng một địa chỉ, liên kết động không thành công và bạn không thể khởi chạy chương trình. Các thư viện có thể yêu cầu các thư viện khác, vì vậy về cơ bản, điều này đòi hỏi mọi thư viện trên hệ thống phải có các địa chỉ logic duy nhất. Tuy nhiên, nó rất nhanh, nếu nó hoạt động. (Đây là cách a.out đã làm mọi thứ, và loại thiết lập mà prelinking làm, sắp xếp).
  2. Nó có thể mã hóa một địa chỉ logic giả và yêu cầu trình liên kết động chỉnh sửa theo đúng địa chỉ khi tải thư viện. Điều này tốn một chút thời gian khi tải các thư viện, nhưng sau đó thì rất nhanh.
  3. Nó có thể thêm một lớp không xác định: sử dụng một thanh ghi CPU để giữ địa chỉ logic mà thư viện được tải vào, và sau đó truy cập mọi thứ như một phần bù từ thanh ghi đó. Điều này áp đặt một chi phí hiệu suất trên mỗi truy cập.

Khá nhiều người không sử dụng số 1 nữa, ít nhất là không phải trên các hệ thống có mục đích chung. Giữ danh sách địa chỉ lôgic duy nhất đó là không thể trên các hệ thống 32 bit (không có đủ để đi xung quanh) và một cơn ác mộng hành chính trên các hệ thống 64 bit. Mặc dù vậy, loại liên kết trước thực hiện điều này trên cơ sở mỗi hệ thống.

Việc số 2 hay số 3 được sử dụng tùy thuộc vào việc thư viện được xây dựng với -fPICtùy chọn (mã độc lập vị trí) của GCC . # 2 là không có, # 3 là với. Nói chung, các thư viện được xây dựng cùng -fPIC, vì vậy # 3 là những gì xảy ra.

Để biết thêm chi tiết, hãy xem Cách viết thư viện chia sẻ (PDF) của Ulrich Drepper .

Vì vậy, cuối cùng, câu hỏi của bạn có thể được trả lời:

  1. Nếu thư viện được xây dựng với -fPIC (vì nó gần như chắc chắn phải như vậy), phần lớn các trang hoàn toàn giống nhau cho mọi quy trình tải nó. Các quy trình của bạn abcũng có thể tải thư viện ở các địa chỉ logic khác nhau, nhưng các địa chỉ đó sẽ trỏ đến cùng các trang vật lý: bộ nhớ sẽ được chia sẻ. Hơn nữa, dữ liệu trong RAM khớp chính xác với những gì trên đĩa, do đó, nó chỉ có thể được tải khi cần bởi trình xử lý lỗi trang.
  2. Nếu thư viện được xây dựng mà không có -fPIC , thì hóa ra hầu hết các trang của thư viện sẽ cần chỉnh sửa liên kết và sẽ khác. Do đó, chúng phải là các trang vật lý riêng biệt (vì chúng chứa dữ liệu khác nhau). Điều đó có nghĩa là chúng không được chia sẻ. Các trang không khớp với những gì trên đĩa, vì vậy tôi sẽ không ngạc nhiên nếu toàn bộ thư viện được tải. Tất nhiên sau đó nó có thể được hoán đổi ra đĩa (trong tệp hoán đổi).

Bạn có thể kiểm tra điều này với pmapcông cụ hoặc trực tiếp bằng cách kiểm tra các tệp khác nhau trong /proc. Ví dụ, đây là một đầu ra (một phần) của pmap -xhai bcs mới được sinh ra khác nhau . Lưu ý rằng các địa chỉ được hiển thị bởi pmap là địa chỉ lôgic điển hình:

pmap -x 14739
Address           Kbytes     RSS   Dirty Mode  Mapping
00007f81803ac000     244     176       0 r-x-- libreadline.so.6.2
00007f81803e9000    2048       0       0 ----- libreadline.so.6.2
00007f81805e9000       8       8       8 r---- libreadline.so.6.2
00007f81805eb000      24      24      24 rw--- libreadline.so.6.2


pmap -x 17739
Address           Kbytes     RSS   Dirty Mode  Mapping
00007f784dc77000     244     176       0 r-x-- libreadline.so.6.2
00007f784dcb4000    2048       0       0 ----- libreadline.so.6.2
00007f784deb4000       8       8       8 r---- libreadline.so.6.2
00007f784deb6000      24      24      24 rw--- libreadline.so.6.2

Bạn có thể thấy rằng thư viện được tải thành nhiều phần và pmap -xcung cấp cho bạn thông tin chi tiết về từng phần riêng biệt. Bạn sẽ nhận thấy rằng các địa chỉ logic khác nhau giữa hai quy trình; bạn có thể mong đợi chúng giống nhau một cách hợp lý (vì cùng một chương trình đang chạy và máy tính thường có thể dự đoán được như vậy), nhưng có một tính năng bảo mật được gọi là ngẫu nhiên bố trí không gian địa chỉ , ngẫu nhiên chúng ngẫu nhiên.

Bạn có thể thấy từ sự khác biệt về kích thước (Kbytes) và kích thước lưu trú (RSS) mà toàn bộ phân khúc thư viện chưa được tải. Cuối cùng, bạn có thể thấy rằng đối với các ánh xạ lớn hơn, bẩn là 0, có nghĩa là nó tương ứng chính xác với những gì trên đĩa.

Bạn có thể chạy lại pmap -XXvà nó sẽ hiển thị cho bạn tùy thuộc vào phiên bản kernel mà bạn đang chạy, vì đầu ra -XX thay đổi theo phiên bản kernel mà ánh xạ đầu tiên có Shared_Clean176, khớp chính xác với RSS. Sharedbộ nhớ có nghĩa là các trang vật lý được chia sẻ giữa nhiều quy trình và vì nó khớp với RSS, điều đó có nghĩa là tất cả các thư viện trong bộ nhớ đều được chia sẻ (xem phần Xem thêm bên dưới để biết thêm về chia sẻ so với riêng tư):

pmap -XX 17739
         Address Perm   Offset Device   Inode  Size  Rss Pss Shared_Clean Shared_Dirty Private_Clean Private_Dirty Referenced Anonymous AnonHugePages Swap KernelPageSize MMUPageSize Locked                   VmFlagsMapping
    7f784dc77000 r-xp 00000000  fd:00 1837043   244  176  19          176            0             0             0        176         0             0    0              4           4      0       rd ex mr mw me sd  libreadline.so.6.2
    7f784dcb4000 ---p 0003d000  fd:00 1837043  2048    0   0            0            0             0             0          0         0             0    0              4           4      0             mr mw me sd  libreadline.so.6.2
    7f784deb4000 r--p 0003d000  fd:00 1837043     8    8   8            0            0             0             8          8         8             0    0              4           4      0       rd mr mw me ac sd  libreadline.so.6.2
    7f784deb6000 rw-p 0003f000  fd:00 1837043    24   24  24            0            0             0            24         24        24             0    0              4           4      0    rd wr mr mw me ac sd  libreadline.so.6.2


Xem thêm


Điều đó có nghĩa là việc prelinking không còn được sử dụng nữa (và việc -fPICsử dụng đã hoàn toàn thay đổi một thời gian trước đây)?
Hauke ​​Laging

@crisron Cảm ơn bạn đã sửa chữa. FYI, Markdown sẽ tính cho bạn, kết quả đầu ra 1. được lặp lại của tôi là chính xác. Ngoài ra, tôi đã thực hiện một vài thay đổi đối với những gì bạn đã làm "địa chỉ bắt đầu" là thuật ngữ kỹ thuật, tôi có thể gây nhầm lẫn bằng cách đặt "logic" ở giữa. Tôi đã thay đổi nó để thoát khỏi biệt ngữ. Ngoài ra, các trang tương đương với các địa chỉ đó, AFAIK không thể có các địa chỉ đó là một trang khác. Tôi đã thử lại, hoán đổi đơn đặt hàng, hy vọng điều đó rõ ràng hơn.
derobert

chết tiệt, bây giờ đó là một câu trả lời !!!
Evan Carroll
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.