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

Tìm hiểu về Intermediate Language – Phần 2 pot

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 (133.74 KB, 11 trang )

Tìm hiểu về Intermediate
Language – Phần 2

Garbage Collection
Garbage collector là một thành phần quản lí bộ nhớ của .NET, nó là một
đáp án cho việc thu hồi bộ nhớ của các chương trình thực thi. Từ trước đến
giờ có hai công nghệ được sử dụng cho việc huỷ bộ nhớ trong Windows,
những tiến trình này được yêu cầu từ hệ thống:
 Ứng dụng tự làm điều này một cách thủ công.
 Tạo một bộ đếm tham chiếu đến đối tượng.
Việc mã ứng dụng chịu trách nhiệm thu hồi vùng nhớ là một cộng nghệ
dùng ở mức thấp, hoặc những ngôn ngữ thực thi cấp cao như C++. Nó mang
tính hiệu quả cao, nó có thuận lợi là tài nguyên sẽ được giải phóng ngay khi
không còn cần thiết. Một bất lợi lớn là nó thường xuyên sinh lỗi. Mã nguồn
luôn phải chỉ rõ cho hệ thống biết khi nó không cần dùng bộ nhớ đó nữa . Dễ
dàng nhìn ra rằng kết quả có thể dẫn đến rò rỉ bộ nhớ.
Mặc dù các môi trường phát triển hiện đại có cung cấp một số công cụ giúp
đỡ trong việc phát hiện sự rò rỉ bộ nhớ, nhưng rất khó theo vết, bởi vì nó
không có hiệu lực cho đến khi có một khối lượng lớn bộ nhớ bị rò rỉ:
Windows buộc phải ngưng các tiến trình xử lí. Tại thời điểm này máy tính
chậm đi thấy rõ một sự trả giá cho các yêu cầu bộ nhớ.
Việc duy trì một bộ đếm các tham chiếu là một ân huệ trong COM. Ý tưởng
này cho rằng mỗi thành phần COM chứa một bộ đếm xem có bao nhiêu ứng
dụng đang chứa tham chiếu đến nó. Khi bộ đếm này xuống đến zero, Thành
phần có thể tự hủy nó và giải phóng vùng nhớ cũng như các tài nguyên
tương ứng. Vấn đề ở đây là nó vẫn lệ thuộc vào sự thông báo của các ứng
dụng khi chúng không còn dùng đến các thành phần này nữa. Trong một vài
trường hợp, nó có khả năng tạo ra một vấn đề nghiêm trọng hơn là sự kiểu rò
rỉ C++ thông thường, bởi vì đối tượng COM có thể nằm trong một tiến trình
của riêng nó, điều này có nghĩa là nó sẽ không bao giờ được hủy bởi hệ
thống (chí ít trong rò rỉ kiểu C++, hệ thống có thể giành lại toàn bộ vùng nhớ


khi tiến trình kết thúc).
Thời gian chạy .NET hoàn toàn phụ thuộc vào garbage collector instead.
Đây là một chương trình hỗ trợ việc thu dọn bộ nhớ. Trong ý tưởng này tất
cả các yêu cầu bộ nhớ đều được cấp phát trên heap (điều này đúng cho tất cả
các ngôn ngữ, trong .NET, CLR chứa nó trong vùng heap có quản cho tất cả
các ứng dụng .NET sử dụng). Thỉnh thoảng .NET sẽ kiểm tra xem vùng
heap có quản có trở nên đầy chưa để nó tiến hành thu dọn, và nó gọi đây là
tiến trình thu gôm rác. Trình thu dọn rác sẽ kiểm tra các tham chiếu từ mã
của bạn, ví dụ các tham chiếu từ mã của bạn đến các đối tượng được lưu trên
heap được nhận dạng, nó có nghĩa là đối tượng đó vẫn còn tham chiếu, các
đối tượng không còn tham chiếu nữa sẽ bị huỷ.
Trình thu gom rác hoạt động trong .NET bởi vì Intermediate Language được
thiết kế để làm điều đó. Phải tuân thủ các nguyên tắc sau, thứ nhất bạn chỉ có
thể tham chiếu đến một đối tượng có sẵn bằng cách sao chép cac tham chiếu
có sẵn, thứ hai Intermediate Language bảo vệ kiểu, điều này có nghĩa là các
tham chiếu đến các đối tượng có sẵn luôn chứa đựng thông tín nhận dạng
chính xác của đối tượng đó.
C++ Có thể không sử dụng trình thu gom một cách máy móc, bởi vì C++
cho phép các con trỏ tự do ép kiểu.
Một điều đặc biệt quản trọng là tính không định trước của trình thu gom rác.
Hay nói cách khác, bạn không thể bảo đảm được khi nào trình thu gôm rác
sẽ được gọi; nó sẽ được gọi khi CLR cảm thấy cần (nếu bạn không thực hiện
lời gọi tường minh).
Bảo mật
.NET thật sự xuất sắc trong việc bổ sung cơ chế bảo mật của Windows bởi
vì nó hỗ trợ code-based security trong khi đó Windows chỉ thật sự hỗ trợ
Role-based security.
Role-based security là cơ sở để xác định tài khoản của các tiến trình đang
thực thi, hay nói cách khác ai sở hữu các tiến trình đang thực thi. Code-
based security là một cơ chế khác để xác định xem những mã nào và có bao

nhiêu mã là đáng tin. Cảm ơn sự bảo vệ kiểu mạnh của IL, vì nhờ nó mà
CLR có thể kiểm tra mã trước khi chạy trong một chế độ bảo vệ được đưa
ra.NET cũng hỗ trợ một cơ chế những mã nào được phép phơi tra trong một
cơ chế bảo mật nào đó.
Một điều quan trọng là code-based security có thể làm giảm nguy cơ liên
quan đến việc chạy các đoạn mã có xuất xứ không rõ ràng (chẳng hạn như
mã mà bạn downloaded từ Internet). Một ví dụ, nếu mã được chạy dưới
quyền administrator, nó có thể sử dụng code-based security để khai báo rằng
mã không còn cho phép thực thi trong những kiểu mà quyền administrator
hỗ trợ như: không thể đọc hoặc viết lên các biến môi trường, đọc hoặc viết
lên registry, không truy cập vào các đặc trưng trong .NET.
Security sẽ được bàn kĩ hơn trong chương 23.
Application Domains
Application domains là một cách tân quan trọng trong .NET và nó được thiết
kế để có thể dễ dàng xử li các vấn đề khi chạy các ứng dụng cần sự biệt lập
với các ứng dụng khác nhưng vẫn có thể thông tin với các ứng dụng khác.
Một ví dụ cổ điển đó lá một ứng dụng web server application, nó phải phản
hồi lại với một số lượng các yêu cấu từ các trình duyệt. Chắc chắn rằng sẽ
tồn tại cùng lúc nhiều thành phần có khả năng phản hồi để phục vụ cho các
yêu cầu đó.
Trước thời .NET, sự lựa chọn giữa cho phép các thể hiện đó có thể dùng
trong một tiến trình, cái mà sẽ mang lại sự rủi ro có thể làm giảm độ an toàn
của trang web, hay là cho phép các thể hiện đó chạy trên các tiến trình biệt
lập, cái mà sẽ mang lại sự gia tăng sự thực thi.
Giờ đây, đó là sự biệt lập mã thông qua các tiến trình. Khi bạn kích khởi một
ứng dụng mới, nó sẽ chạy trong ngữ cảnh của tiếnt trình. Các tiến trình
Windows độc lập nhau thông qua vùng địa chỉ. Trong ý tưởng này mỗi tiến
trình sẽ có sẵn 4 gigabytes bộ nhớ ảo để chữa dữ liệu và mã thực thi (4GB là
dành cho hệ thống 32-bit; hệ thống 64-bit có thể nhiều hơn). Windows gián
tiếp thực hiện cơ chê mở rộng để ánh xạ bộ nhớ ảo này với bộ nhớ vật lí thật

hay đĩa. Mỗi tiến trình sẽ có sự ánh xạ khác nhau, sao cho các vùng nhớ vật
lí thật sự không trùng lấp nhau. Nó được minh họa bởi sơ đồ sau:

Một cách tổng quat, bất kì tiến trình nào cũng chỉ có thể truy cập đến bộ nhớ
thông qua mộ địa chỉ ảo cụ thể - các tiến trình không thể truy xuất trực tiếp
bộ nhớ vật lí. Như vậy nó đơn giản là không cho phép một tiến trình có thể
truy xuất đến vùng nhớ được cấp cho một tiến trình khác. Nó cung cấp một
cơ chế bảo đảm rằng những ứng xử tồi của mã không thể làm hỏng bất kì
thứ gì bên ngoài vùng địa chỉ của nó. (chú ý rằng trong Windows 9x, những
cơ chế bảo vệ này không đươc thấu đáo như trong NT/2000/XP, vì thế về
mặt lí thuyết các ứng dụng có khả năng phá hủy Windows do viết lên vùng
nhớ không thích hợp).
Các tiến trình không chỉ phục vụ như là cách để tạo nên sự tách biệt giữa các
thể hiện khác nhau. Trong hệ thống Windows NT/2000, nó còn làm đơn vị
để gán các giấy phép và đặc quyền bảo mật. Mỗi tiến trình có một kí hiệu
bảo mật riêng, để báo cho Windows biết chính xác các thực thi mà tiến trình
cho phép.
Cả hai phương pháp này đều có khả năng bảo mật tốt nhưng lại sinh ra một
bất lợi lớn đó là thực thi. Thông thường các tiến trình sẽ hoạt động chung
với nhau, bởi vậy cần phải có sự truyền thông giữa chúng. Ví dụ như đâu đó
một tiến trình gọi một thành phần COM khả thi, và bởi vì được yêu cầu chạy
trong tiến trình của chúng. Giống như cách mà COM vẫn làm. Khi đó các
tiến trình không thể dùng chung bộ nhớ, một tiến trình phức tạp được sử
dụng để sao chép dữ liệu giữa các tiến trình. Nó sẽ gây trở ngại lớin đến vấn
đề thực thi. Nếu bạn muốn các thành phần có thể làm việc với nhau mà
không muốn ảnh hưởng đến vấn đề thực thi, cách duy nhất là sử dụng DLL-
based components và mọi thứ sẽ hoạt động trong cùng một vùng đã chỉ (đây
là một việc mạo hiểm vì các thành phần ứng xử tồi sẽ làm hỏng tất cả mọi
thứ).
Application domains được thiết kế như là một thành phần riêng biệt không

gây ảnh hưởng đến vấn đề thực thi trong lúc các tiến trình trao đổi dữ liệu. Ý
tưởng này cho rằng một tiến trình được chia thành một số các application
domains. Mỗi application domain sẽ trả lời cho một ứng dụng đơn, và các
loạt thực thi sẽ hoạt động như là một application domain độc lập:

Nếu các thực thi cúng sử dụng chung một vùng nhớ, rõ ràng chúng có thể
dùng chung dữ liệu, bởi vì trên lí thuyết chúng có thể truy xuất trục tiếp dữ
liệu của nhau. Tuy nhiên đó chỉ là nguyên tắc, CLR sẽ bảo đảm rằng điều
này sẽ không xảy ra trong thực tế bằng cách kiểm tra kỹ lưỡng mã trong mỗi
ứng dụng, để chắc rằng chúng không lạc ra khỏi vùng dữ liệu của chúng.
Trước tiên hầu như các trò bịp quá đáng sẽ bị loại bỏ, sau đó ứng dụng có
thể hoạt động và không phải kích hoạt nó.
Thật sự, nó hoàn toàn có thể làm được điều này vì sự định kiểu mạnh của IL.
Trong nhiều trường hợp, nếu mã thật sự dùng kiểu không quản chẳng hạn
như các con trỏ, kiểu dữ liệu đang dùng sẽ bảo đảm vùng nhớ sẽ được truy
cập hợp lí. ví dụ, kiểu mảng .NET sẽ tiến hành kiểm tra và bảo đảm rằng các
thao tác trên mảng đều nằm trong phạm vi cho phép. Nếu một thực thi cần
trao đổi thông tin với các thực thi chạy trong các application domain khác
chúng phải gọi dịch vụ điều khiển từ xa của .NET.
Mã được kiểm tra xem có truy cập dữ liệu ngoài application domain không
được gọi là memory type-safe. Như vậy mã này có thể hoạt động cùng với
mã được bảo vệ ở các application domains khác nhau trong cùng một tiến
trình.
Bẫy lỗi thông qua các ngoại lệ
.NET được thiết kế để đơn giản hoá quá trình bẫy lỗi thông qua các ngoại lệ.
Những nhà phát triển C++ nên biết rằng, bởi vì IL là hệ thống định kiểu
mạnh, nó không thực thi các mối kết hợp bất lợi thông qua các ngoại lệ trong
IL, đây là cách được đưa ra trong C++. Tất nhiên khối finally cũng được hỗ
trợ trong .NET và C#.
Chúng ta sẽ bàn kĩ về ngoại lệ trong chương 4. Sơ qua một chút, ý tưởng ở

đây là một vùng mã được thiết kế như là các thủ tục quản ngoại lệ, mỗi đoạn
mã có thể giải quyết một điêu kiện lỗi riêng (ví dụ, một file không được tìm
thấy, hoặc không được phép thực thi một số lệnh). Những điều kiện này có
thể được định nghĩa kĩ hoặc sơ qua tuỳ bạn. Cấu trúc ngoại lệ bảo đảm rằng
khi một điều kiện sinh lỗi xảy ra, ngay lập tức luồn thi hành sẽ nhảy đến thủ
tục quản ngoại lệ.
Cơ cấu quản ngoại lệ tạo điều kiện thuận lợi để truyền cho một đối tượng
thông tin chính xác về các điều kiện sinh ngoại lệ và một thủ tục quản ngoại
lệ. Đối tượng này có thể bao gồm một thông điệp thích hợp cho người dùng
và chi tiết về nơi phát sinh ngoại lệ.
Hầu hết các cơ cấu quản ngoại lệ, bao gồm cả điều khiển của chương trình
sẽ treo khi một ngoại lệ được phát sinh, được quản bởi ngôn ngữ bậc cao
(C#, VB.NET, C++), và không một lệnh IL nào hỗ trợ việc đó. Ví dụ C#,
quản sự kiện thông qua các khối mã try{}, catch{}, finally{}, chúng ta sẽ
bàn sau trong chương 4.
Những gì mà .NET làm là cung cấp cơ sở cho phép các trình biên dịch
hướng .NET hỗ trợ việc quản ngoại lệ. Cụ thể nó cung cấp một bộ các lớp
.NET có thể miêu tả các ngoại lệ, và thực thi ngôn ngữ chéo cho phép truyền
các đối tượng ngoại lệ cho các mã quản ngoại lệ, bất chấp mã quản ngoại lệ
được viết trong ngôn ngữ nào. Sự độc lập ngôn ngữ này không được hỗ trợ
trong việc quản ngoại lệ của C++ lẫn Jave, mặc dù nó vẫn tồn tại giới hạn
trong cơ cấu COM cho việc quản lỗi: bao gồm việc trả về mã lỗi trong các
phương thức và truyền các đối tượng lỗi. Thật vậy các ngoại lệ đó được quản
một cách nhất quán trong các ngôn ngữ khác nhau nó đóng vai trò quyết
định trong phát triển đa ngôn ngữ.
Dùng các thuộc tính
Attributes là một đặc trưng đã thân thuộc với những nhà phát triển C++ để
viết các thành phần COM (thông qua việc sử dụng Microsoft's COM
Interface Definition Language (IDL)) dù vậy nó không thân thiện với những
nhà phát triển Visual Basic hay Java. Attribute cung cấp thông tin mở rộng

liên quan đến các mục trong chương trình có thể được sử dụng bởi trình biên
dịch.
Attributes được hỗ trợ trong .NET - và vì thế giờ đây nó được hỗ trợ trong
C++, C#, và VB.NET. Một cái mới là các attribute trong .NET là một cơ chế
cho phép bạn có thể định nghĩa các attribute của riêng bạn trong mã nguồn.
Các attribute tự định nghĩa này có thể thay thế cho các siêu dữ liệu của các
phương thức và kiểu dữ liệu tương ứng. .Do tính độc lập ngôn ngữ của .NET
mà các attribute có thể được định nghĩa trong một ngôn ngữ và có thể đọc
bằng mã ở các ngôn ngữ khác.
Attributes sẽ được bàn trong chương 5 của cuốn sách này.

×