Tải bản đầy đủ (.pdf) (14 trang)

tiểu luận môn Nguyên lý các ngôn ngữ lập trình. Đề tài tìm hiểu Kỹ thuật Garbage collection

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (246.92 KB, 14 trang )

TRƯỜNG ĐẠI HỌC BÁCH KHOA HÀ NỘI
VIỆN CÔNG NGHỆ THÔNG TIN & TRUYỀN THÔNG

BÀI TẬP LỚN
MÔN: NGUYÊN LÝ NGÔN NGỮ LẬP TRÌNH
ĐỀ TÀI: KỸ THUẬT GARBAGE COLLECTION

GIẢNG VIÊN HƯỚNG DẪN: TS NGUYỄN HỮU ĐỨC
HỌC VIÊN: NGUYỄN MẠNH HÀ
CB111398
NGUYỄN VĂN CƯỜNG CB121350
NGÔ THANH TÂN
CB121356
ĐINH VĂN VIỆT
CB121363

0


LỜI MỞ ĐẦU

Thế kỷ 21 mở ra một thời đại mới, thời đại khoa học công nghệ đòi hỏi con
người luôn luôn không ngừng tìm tòi học tập để tiến bộ. Với sự nhảy vọt của
khoa học, các kỹ thuật thực hiện trong ngành Công nghệ thông tin ngày càng
phát triển, chỉ trong thời gian ngắn nó đã đạt được những thành tựu to lớn ở hầu
hết các lĩnh vực khác nhau trong đời sống xã hội. Kỹ thuật dọn rác (Garbage
Collector) là một tiến trình đặc biệt có nhiệm vụ duyệt qua các vùng nhớ đã
được cấp phát và kiểm tra xem vùng nhớ nào không còn được sử dụng nữa
(không còn tham chiếu tới nó nữa) thì sẽ thực hiện thu hồi một cách tự động để
có thể cấp phát cho các yêu cầu tiếp theo. Vấn đề chúng ta cần biết ở đây là,
“làm thế nào Garbage Collector có thể biết được rằng vùng nhớ đó không còn


được sử dụng nữa để mà thu hồi?”
Trong bài tiểu luận này, chúng em xin trình bày về “Kỹ thuật Garbage
Collection”
Em xin chân thành cảm ơn thầy TS.Nguyễn Hữu Đức đã hướng dẫn và tạo
mọi điều kiện tốt nhất để nhóm em hoàn thành tốt bài tiểu luận này.

1


MỤC LỤC

1. Các khái niệm về Garbage Collection (GC- bộ dọn rác) .............................. 3
2. Biến đếm trong GC ..................................................................................... 5
3. Mark-Sweep Collection - [McCarthy 1960]................................................. 7
4. Mark-Compact Collection (Nén sau khi đánh dấu) .................................... 10
5. Copying Garbage Collection ..................................................................... 10
6. Non-Copying Implicit Collection .............................................................. 12
LỜI KẾT ....................................................................................................... 13
TÀI LIỆU THAM KHẢO ............................................................................. 14

2


1. Các khái niệm về Garbage Collection (GC- bộ dọn rác)
Trong quá trình lập trình ví dụ như C+ + thì chắc hẳn sẽ nhớ đến một trong
những điểm mạnh và cũng rất phức tạp của ngôn ngữ này là con trỏ và cấp phát
động bộ nhớ. Giả sử như sau khi kết thúc chương trình mà chúng ta không thu
hồi vùng nhớ này thì chuyện gì sẽ xảy ra? Các ô nhớ này sẽ cứ tồn tại trong bộ
nhớ trong khi các chương trình khác không thể sử dụng được vùng nhớ này (hay
còn gọi là rò rỉ bộ nhớ – memory leak). Vì thế, yêu cầu bắt buộc là sau khi sử

dụng xong vùng nhớ đã cấp phát thì phải thu hồi.
Trong .NET (cũng như Java) có một khái niệm là Bộ dọn rác (Garbage
Collector). Đây là một tiến trình đặc biệt có nhiệm vụ duyệt qua các vùng nhớ
đã được cấp phát và kiểm tra xem vùng nhớ nào không còn được sử dụng nữa
(không còn tham chiếu tới nó nữa) thì sẽ thực hiện thu hồi một cách tự động để
có thể cấp phát cho các yêu cầu tiếp theo.
Chúng ta có thể hình dung được công việc của Garbage Collector như sau:
Khi chương trình khởi chạy thì một vùng nhớ liên tục còn trống sẽ được dành
riêng để cấp phát cho các biến trong chương trình (vùng nhớ này được gọi là
managed-heap). Khi chúng ta dùng toán tử new để tạo một đối tượng mới thì
chương trình sẽ kiểm tra xem vùng nhớ này còn đủ để cấp phát hay không, nếu
không đủ thì GC sẽ được khởi động. Bước đầu tiên mà GC thực hiện là tạm
dừng chương trình và thực hiện việc duyệt để đánh dấu tất cả những vùng nhớ
đang được sử dụng với khởi đầu tại một điểm nào đó đã biết trước (hay được gọi
là điểm gốc). Vì vậy ta có thể hiểu:
* Garbage Collection (GC)
-Tự động khôi phục bộ nhớ.
- Chức năng của GC là tìm những đối tượng dữ liệu không còn sử dụng nữa
và giải phóng chúng bởi chương trình đang chạy.
* Tại sao cần GC?
3


Nếu tiến trình không giải phóng bộ nhớ đã sử dụng, khoảng trống không sử
dụng sẽ ngày càng tăng cho đến khi tiến trình chấm dứt hoặc việc trao đổi không
gian nhớ sẽ không còn.
*Rào cản trong quản lý bộ nhớ
- Lỗi lập trình có thể dẫn đến lỗi trong quản lý bộ nhớ:
+ Có thể giải phóng vùng nhớ sớm hơn khi cần.
+ Có thể không giải phóng hết vùng nhớ có thể, là nguyên nhân gây ra

thiếu bộ nhớ.
- Những lỗi này đặc biệt nguy hiểm vì thường xuất hiện sau khi phân bổ,
rất khó gỡ rối.
- Nhiều lập trình viên cấp phát object tĩnh, tránh cấp phát trên heap để khỏi
quan tâm khi nào giải phóng chúng
- Trong nhiều hệ thống lớn, GC được thực thi trong những đối tượng hệ
thống (system’s objects).
- GC thì không được hỗ trợ bởi ngôn ngữ lập trình.
- Gây ra lỗi và không tin cậy, những bộ dọn rác riêng lẻ thường không được
sử dụng bởi những ứng dụng khác.
Vì vậy mục đích của GC là giải quyết những các vấn đề trên
* Tính phức tạp của GC
- GC đôi khi được xem là có chi phí rẻ hơn việc giải phóng tường minh
- Một GC tốt làm chương trình chậm 10%.
- Dù có vẻ nhiều nhưng đó là một cái giá thấp để trả cho:
+ Sự tiện lợi (Convenience);
+ Thời gian phát triển (Development time);
+ Độ tin cậy (Reliability).
* Hai phase chính của GC
- Dò tìm rác (garbage detection):
4


+ Phân biệt những đối tượng sống (live objects) từ rác
- Giải phóng rác (garbage reclamation):
+Giải phóng vùng nhớ của các đối tượng rác, để chương trình đang
chạy có thể sử dụng nó
Trong thực tế thì 2 phase này xen kẽ nhau
2. Biến đếm trong GC
Mỗi đối tượng kết hợp với 1 biến đếm số tham chiếu đến nó.

Mỗi khi có 1 tham chiếu đến đối tượng được tạo, biến đếm tham chiếu sẽ
tăng lên 1 và ngược lại.
Khi biến đếm tham chiếu bằng 0, vùng nhớ dành cho đối tượng có thể được
giải phóng.

Khi đối tượng được giải phóng, thì biến đếm tham chiếu của những đối
tượng mà đối tương này trỏ đến sẽ giảm xuống
Việc giải phóng một đối tượng có thể kéo theo việc giải phóng của hàng
loại đối tượng khác
Đó là 2 vấn đề chính của việc tìm hiểu biến đếm
Garbage Collection gồm 2 giai đoạn: việc điều chỉnh và kiểm tra biến đếm
sẽ được thực hiện ở giai đoạn đầu, và việc giải phóng sẽ xảy ra khi biến đếm
5


bằng 0, cả 2 thao tác này đều phải được xen vào khi chương trình thực thi. Bởi
vì chúng có thể xay ra bất cứ khi nào con trỏ được tạo ra hoặc giải phóng.
Một ưu điểm của sử dụng biến đếm là việc cập nhật biến đếm được xen vào
khi chương trình đang thực thi, việc này có thển thực hiện một cách dễ dàng. Rõ
ràng việc cập nhật biến đếm không bao giờ liên quan đến các thao tác để chương
trình có thể thực thi. Việc giải phóng hàng loạt toàn bộ các cấu trúc dữ liệu có
thể bị trì hoãn, bởi khi đã có một danh sách các đối tượng garbage mà biến đếm
của chúng bằng 0 thì việc giải phóng vẫn chưa được xử lý.
Việc thu gom tăng cường này có thể dễ dàng thỏa mãn yêu cầu về thời gian
thực, đảm bảo các thao tác quản lý bộ nhớ sẽ không trì hoãn chương trình khi
chương trình thực thi. Điều này có thể hỗ trợ chương trình khi mà việc đảm bảo
về thời gian là then chốt. Đồng thời việc thu gom tăng cường cũng đảm bảo cho
chương trình thực thi 1 cách hiệu quả thông qua việc giảm bớt số lượng các
công việc mà người lập trình cần phải làm(thu gom rác).
* Vấn đề cấu trúc vòng

Biến đếm thất bại khi giải phóng cấu trúc vòng, nguyên nhân từ việc xác
định rác. Cấu trúc vòng không hiếm trong các chương trình ngày nay(Cây,Cấu
trúc dữ liệu vòng). Khi đó giải pháp được chuyển về cho lập trình viên
* Hiệu quả của biến đếm
- Khi một con trỏ được tạo, biến đếm tham chiếu của đối tượng mà nó trỏ
đến phải được điều chỉnh.
+ Nếu giá trị của biến con trỏ được chuyển từ con trỏ này đến con trỏ
khác(phép gán), thì hai biến đếm của cả hai con trỏ phải được cập nhật, một biến
RC của 1 đối tượng sẽ tăng còn biến kia sẽ giảm.
+Sau đó phải kiểm tra biến đếm=0 hay không
- Những biến ngăn xếp mà có thời gian sống ngắn sẽ phải chịu chi phí lớn
cho mô hình biến đếm. Trong trường hợp này biến đếm tham chiếu được tăng
lên và giảm trở lại nhanh chóng.
6


*Biến đếm cục bộ
- Phần lớn chi phí có thể tối ưu bằng cách sử dụng biến cục bộ
- Tham chiếu từ biến cục bộ không cần giữ lại. Chúng ta chỉ cần điều chỉnh
biến đếm trong heap.
Tuy nhiên chúng ta không thể bỏ qua hoàn toàn các con trỏ trong stack. Vì
vậy stack được quét trước khi đối tượng được giải phóng và chỉ khi biến đếm
của con trỏ =0 thì nó được giải phóng.
Hạn chế cập nhật biến đếm của đối với con trỏ trong stack sẽ giảm đáng kể
chi phí của biến đếm.
3. Mark-Sweep Collection - [McCarthy 1960]
- Phân biệt đối tượng sống từ rác (Mark phase)
- Thực hiện bằng đánh dấu – bắt đầu ở root set và duyệt qua đồ thị các con
trỏ có thể đến được:
+ Đánh dấu những đối tượng đi qua

+ Thu hồi vùng nhớ rác (Sweep phase)
- Sau Mark phase, bộ nhớ sẽ được kiểm tra kỹ lưỡng để tìm ra những đối
tượng không được đánh dấu(rác) và thu hồi chúng
-Dùng 1 bit làm mark-bit.
1 : đánh dấu
0 : không đánh dấu
*Ví dụ:
root

ro

Free_li

Before

7
Mark phase


*Thuật toán cơ bản
New(A)=

mark(Obj)=

if free_list is empty

if mark_bit(Obj) == unmarked

mark_sweep()


mark_bit(Obj)=marked

if free_list is empty

for C in Children(Obj)

return (“out-of-memory”)

mark(C)

pointer = allocate(A)
return (pointer)

mark_sweep()=
for Ptr in Roots
mark(Ptr)
sweep()

Sweep()=
p = Heap_bottom
while (p < Heap_top)
if (mark_bit(p) == unmarked) then free(p)
else mark_bit(p) = unmarked; p=p+size(p)

* Tính chất của Mark & Sweep
- Phân mảnh:
+ Khó cấp phát những đối tượng lớn.
+ Vài đối tượng nhỏ có thể lấy nhiều khoảng trống kế tiếp.
- Chi phí:
+ Tỉ lệ với kích thước heap, gồm cả đối tượng sống và rác.

- Locality of reference:
+ Không di chuyển đối tượng
8


+ Đối tượng được đặt lẫn lộn là nguyên nhân nhiều page swaps
(Thông thường thì những đối tượng trong cluster thường được active cùng
lúc).
*Ưu điểm:
- Không cần cấp thêm vùng nhớ để lưu trữ trường count.
- Các object không cần di chuyển trong quá trình GC.
- Loại bỏ được rác trong trường hợp có tham chiếu vòng (cyclic structures).
*Nhược điểm:
- Giới hạn giá trị lớn nhất có thể của ô nhớ (integer).
- Tăng khả năng làm phân mảnh vùng nhớ.
- Chương trình phải tạm dừng khi GC thực thi.
- Giai đoạn sweep tốn chi phí cao (thời gian).
4. Mark-Compact Collection (Nén sau khi đánh dấu)
- Mark-Compact giải quyết vấn đề phân mảnh và cấp phát của mark-sweep
- Bộ dọn rác sẽ duyệt qua đồ thị con trỏ và thực hiện sao chép từng đối
tượng sống sau bước này
- Kết quả là một vùng trống liên tục tiếp theo. Đối tượng sống ở một phía
và rác ở cũng như vùng trống ở một phía
- Những đối tượng rác được nén về cuối bộ nhớ
- Tiến trình sẽ trải qua một số bước trên bộ nhớ:
+ Một để tính vị trí mới của đối tượng (địa chỉ)
+ Cập nhật con các con trỏ và di chuyển các đối tượng
- Thuật toán này chậm hơn đáng kể so với Mark-Sweep
- Hai thuật toán ví dụ về Mark-Compact:
+ Two-finger Alg– cho những đối tượng có cùng kích thước

+ Lisp 2 Alg
9


5. Copying Garbage Collection
- Giống Mark-Compact, thuật toán di chuyển tất cả live objects vào một
khu vực, phần còn lại của heap được giải phóng.
- Có một vài phương thức cho copying GC, “Stop and-Copy” là một ví dụ.
*Stop-and-Copy Collector
- Bộ nhớ heap được chia làm 2 phần.
- Khi chương trình đang chạy yêu cầu cấp phát mà không còn đủ vùng nhớ
chưa sử dụng.
- Chương trình sẽ dừng và copying GC Được gọi để thu hồi khoảng trống.

* Thuật toán

New(n)=

Init()=
Tospace=Heap_bottom

If free+n>top_of_space

space_size=Heap_size/2

Collect()
if free+n>top_of_space

top_of_space=Tospace+space_size


abort“Memoryexhausted”

Fromspace=top_of_space+1

new-object=free

free=Tospace

free=free+n
10


return(new-object)
collect()=
from-space,to-space=
to-space,fromspace//swap
scan=free=Tospace

copy(P)=
ifforwarded(P)
returnforwarding_address(P)
else
addr=free
mem-copy(P,free)
free=free+size(P)
forwarding_address(P)=addr
return(addr)

top_of_space=Tospace+space_size
forRinRoots

R=copy(R)
whilescanforPinchildren(scan)
*P=copy(P)
scan=scan+s
*Hiệu quả Copying Collection
- Thứ tự đối tượng là tùy ý.

- Công việc hoàn thành phụ thuộc số lượng đối tượng sống.
- Để giảm tần suất của GC, cần cấp phát không gian lớn.
- Không thực tế nếu không đủ RAM và phân trang xuất hiện.
* Ưu điểm:
- Giảm khả năng phân mảnh vùng nhớ heap.
- Thời gian thực hiện công việc thì tỉ lệ với các đối tượng sống.
- Có thể xử lý được rác chứa các tham chiếu vòng
- Không tốn bộ nhớ để lưu trường đếm.
* Nhược điểm:
- Vùng nhớ dùng cho chương trình bị chia đôi (fromspace – tospace).
- Các đối tượng phải di chuyển trong vùng nhớ trong suốt quá trình thu
gom rác, do vậy các tham chiếu đến các đối tượng cũng phải cập nhật.
- Chương trình phải tạm dừng khi bộ thu gom rác thực thi.
11


6. Non-Copying Implicit Collection
- Cần thêm 2 trường con trỏ và một trường màu cho mỗi đối tượng. Những
trường này phục vụ cho việc liên kết giữa các vùng nhớ trong một danh sách
liên kết đôi. Trường màu xác định đối tượng thuộc về tập live objects hay tập rác
- Duyệt tất cả các đối tượng trong vùng nhớ heap Các đối tượng live object
sẽ linking đến tập toset, và màu chuyển sang màu khác. Sau khi di chuyển các

live object từ fromset sang thì các object còn lại trong fromset là garbage và có
thể sử dụng như một free list. Sau đó tập hợp fromset sẽ hoán đổi thành
toset(giống như fromspace và tospace trong copying collector)
- Trong hầu hết trường hợp thì chi phí nhỏ hơn copying collector nhưng
trong vài trường hợp thì chi phí phân mảnh có thể quá nặng.
*Ưu điểm:
- Chi phí dò tìm(duyệt- tracing processing) không cao
- Vùng nhớ không cần phải chia đôi, nhưng tốn thêm vùng nhớ để lưu trữ 2
biến con trỏ và trường field color.
-

LỜI KẾT

Quá trình thực hiện dọn dẹp bộ nhớ của kỹ thuật Garbage Collector thật sự
khiến cho chương trình của chúng ta sẽ chạy chậm hơn so với các chương trình
viết bằng C/C++. Tuy nhiên, năng suất mà chúng ta đạt được là rất đáng kể bởi
vì chúng ta không phải tập trung giải quyết những công việc đòi hỏi sự tỉ mỉ, cẩn
thận với ngôn ngữ lập trình mà chỉ cần tập trung vào giải quyết các vấn đề của
khách hàng đưa ra.

12


Một lần nữa, chúng em xin chân thành cảm ơn thầy TS. Nguyễn Hữu Đức
đã tạo mọi điều kiện tốt nhất để chúng em hoàn thành tốt bài tiểu luận này.

TÀI LIỆU THAM KHẢO
1. TS. Nguyễn Hữu Đức - Bài giảng Nguyên lý các ngôn ngữ lập trình.
2. />
13




×