sách gpt4 ai đã đi

C# Giải thích chi tiết về Assembly.Unload

In lại Tác giả:qq735679552 Thời gian cập nhật: 2022-09-27 22:32:09 36 4
mua khóa gpt4 Nike

CFSDN nhấn mạnh vào việc tạo ra giá trị thông qua mã nguồn mở. Chúng tôi cam kết xây dựng một nền tảng chia sẻ tài nguyên để mọi người làm CNTT có thể tìm thấy thế giới tuyệt vời của riêng mình tại đây.

Bài đăng trên blog CFSDN về C# Assembly.Unload này được biên soạn bởi tác giả. Nếu bạn quan tâm đến bài viết này, vui lòng thích nó.

    Trình quản lý đơn vị sản phẩm CLR (Unit Manager) Jason Zander đã giải thích trong một bài viết cách đây vài ngày Tại sao không có phương thức Assembly.Unload? tại sao hiện tại không có phương thức Assembly.Unload trong CLR triển khai chức năng tương tự như hàm UnloadLibrary trong Win32 API. Ông tin rằng lý do triển khai chức năng Assembly.Unload chủ yếu là để giải phóng không gian và cập nhật phiên bản. Phương pháp đầu tiên sẽ thu hồi các tài nguyên mà Assembly chiếm dụng sau khi sử dụng, trong khi phương pháp thứ hai sẽ dỡ bỏ phiên bản hiện tại và tải phiên bản đã cập nhật. Ví dụ, bản cập nhật động của chương trình Assembly được trang trong ASP.NET sử dụng là một ví dụ sử dụng hay. Nhưng nếu cung cấp hàm Assembly.Unload thì sẽ phát sinh một số vấn đề:

    1. Để đảm bảo rằng các địa chỉ mã được tham chiếu bởi mã trong gói CLR là hợp lệ, các ứng dụng đặc biệt như đối tượng GC và COM CCW phải được theo dõi. Nếu không, sau khi Assembly được dỡ tải, vẫn có thể có các đối tượng CLR hoặc thành phần COM sử dụng mã hoặc địa chỉ dữ liệu của Assembly này, điều này sẽ gây ra ngoại lệ truy cập. Để tránh loại theo dõi lỗi này, hiện tại nó được thực hiện ở cấp AppDomain. Nếu hỗ trợ Assembly.Unload được thêm vào, mức độ chi tiết của việc theo dõi phải được giảm xuống cấp Assembly. Mặc dù điều này khả thi về mặt kỹ thuật, nhưng chi phí lại quá cao.

    2. Nếu Assembly.Unload được hỗ trợ, bạn phải theo dõi các xử lý được sử dụng bởi mỗi mã Assembly và các tham chiếu đến mã được quản lý hiện có. Ví dụ, khi JITer biên dịch một phương thức, mã được tạo ra đều nằm trong một vùng thống nhất. Nếu bạn muốn hỗ trợ việc dỡ Assembly, bạn phải biên dịch từng Assembly một cách độc lập. Ngoài ra, còn có một số vấn đề sử dụng tài nguyên tương tự. Mặc dù về mặt kỹ thuật có thể tách biệt việc theo dõi, nhưng chi phí lại cao, đặc biệt là trên các hệ thống có tài nguyên hạn chế như WinCE.

    3. CLR hỗ trợ tối ưu hóa tải Assembly giữa nhiều AppDomain, tức là tối ưu hóa trung lập miền, để nhiều AppDomain có thể chia sẻ một mã và tăng tốc độ tải. Hiện tại, v1.0 và v1.1 không thể xử lý việc dỡ mã loại trung lập miền. Điều này cũng làm cho việc triển khai toàn bộ ngữ nghĩa của Assembly.Unload trở nên khó khăn.

    Dựa trên những vấn đề trên, Jason Zander khuyên bạn nên sử dụng các phương pháp thiết kế khác để tránh sử dụng tính năng này. Ví dụ, AppDomain và Shadow Copy, được Junfeng Zhang giới thiệu trên blog của mình, là cách ASP.NET giải quyết các vấn đề tương tự.

    Khi xây dựng AppDomain, hãy bật chính sách ShadowCopy bằng cách đặt AppDomainSetup.ShadowCopyFiles thành "true" trong tham số AppDomainSetup của phương thức AppDomainSetup.CreateDomain; sau đó đặt AppDomainSetup.ShadowCopyDirectories thành thư mục đích sao chép; đặt AppDomainSetup.CachePath + AppDomainSetup.ApplicationName để chỉ định đường dẫn bộ đệm và tên tệp. Bằng cách này, ngữ nghĩa của Assembly.Unload có thể được mô phỏng. Việc triển khai là tải Assembly cần được quản lý vào một AppDomain được thiết lập động, sau đó gọi các hàm của nó thông qua một proxy trong suốt trên các AppDomain, sử dụng AppDomain.Unload để mô phỏng ngữ nghĩa của Assembly.Unload. chornbe cung cấp một lớp bao bọc đơn giản, mã cụ thể nằm ở cuối bài viết.

    Mặc dù về cơ bản có thể mô phỏng được về mặt ngữ nghĩa nhưng vẫn có nhiều vấn đề và chi phí:

    1. Hiệu suất: Trong CLR, AppDomain là một khái niệm logic tương tự như quy trình hệ điều hành. Giao tiếp giữa các AppDomain phải tuân theo nhiều hạn chế, giống như giao tiếp giữa các quy trình trước đó. Mặc dù các đối tượng proxy trong suốt có thể được sử dụng để triển khai các chức năng tương tự như các cuộc gọi đối tượng COM xử lý chéo và tự động hoàn tất các hoạt động sắp xếp tham số, nhưng chúng phải trả giá khá đắt. Trong ví dụ do Dejan Jelovic đưa ra (Các cuộc gọi liên ứng dụng cực kỳ chậm), các cuộc gọi chỉ sử dụng các kiểu tích hợp mất khoảng 1ms trên P4 1.7G. Điều này quá tốn kém đối với một số chức năng cần được gọi thường xuyên. Như ông đã đề cập, để triển khai một plug-in vẽ, việc vẽ 200 điểm trong OnPaint cần chi phí cuộc gọi là 200ms. Mặc dù có thể đạt được khả năng tối ưu hóa thông qua các lệnh gọi hàng loạt, nhưng việc giảm hiệu quả của các lệnh gọi xuyên AppDomain chắc chắn là không thể tránh khỏi. May mắn thay, người ta nói rằng trong Whidbey, các kiểu tích hợp trong các cuộc gọi liên AppDomain có thể được tối ưu hóa mà không cần Marshal, do đó tốc độ cuộc gọi có thể nhanh hơn 7 lần so với triển khai hiện tại... Tôi không biết nên khen triển khai của Whidbey hay nên chê phiên bản hiện tại là tệ, haha.

    2. Dễ sử dụng: Các kiểu trong Assembly cần được gỡ cài đặt riêng có thể không hỗ trợ Marshal, do đó bạn cần tự mình xử lý việc quản lý kiểu.

    3. Phiên bản: Cách đóng gói phiên bản tải chính xác trong nhiều AppDomain.

    Ngoài ra còn có vấn đề về an ninh. Đối với Assembly.Load thông thường, Assembly đã tải chạy dưới sự chứng minh của trình tải, đây chắc chắn là một rủi ro bảo mật. Nó có thể dễ bị tấn công tương tự như chương trình trên Unix tràn để đọc và ghi các tệp có quyền root để ghi lại các tệp hệ thống. Bằng cách tải Assembly vào một AppDomain duy nhất, bạn có thể thiết lập quyền CAS riêng biệt và giảm quyền thực thi. Do cơ chế kiểm soát quyền bốn cấp theo kiến ​​trúc CLR nên mức độ chi tiết tốt nhất chỉ có thể là AppDomain. May mắn thay, Whidbey được cho là sẽ bổ sung hỗ trợ cho việc tải cụm với các bằng chứng khác nhau.

    Qua những thảo luận này, chúng ta có thể thấy rằng ngữ nghĩa của Assembly.Unload rất quan trọng đối với các chương trình dựa trên mô hình plug-in. Tuy nhiên, hiện tại và trong các phiên bản gần đây, việc mô phỏng ngữ nghĩa của nó thông qua AppDomain là lựa chọn phù hợp hơn. Mặc dù có vấn đề về hiệu suất và khả năng sử dụng, nhưng nó có thể kiểm soát các yếu tố như chức năng và bảo mật ở mức độ lớn hơn. Về lâu dài, việc triển khai Assembly.Unload hoàn toàn khả thi. Việc dỡ bỏ các lớp trong Java là ví dụ tốt nhất. Các lý do trước đây thực sự là vấn đề về khối lượng công việc và độ phức tạp, và không có vấn đề kỹ thuật nào không thể giải quyết được.

chornbe

Bạn cũng phải đóng gói assembly đã tải vào một lớp khác, được tải bởi appdomain mới. Đây là mã khi nó hoạt động với tôi: (Tôi đã tạo một số loại ngoại lệ tùy chỉnh và bạn sẽ thấy tôi đã lấy lại chúng - chúng không phải là hậu duệ của MarshalByRefObject nên tôi không thể chỉ ném chúng từ mã được đóng gói).

--- cắt tập hồ sơ hạng nhất.

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
hai mươi mốt
hai mươi hai
hai mươi ba
hai mươi bốn
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
sử dụng Hệ thống;
sử dụng Hệ thống.Phản chiếu;
sử dụng Hệ thống.Bộ sưu tập;
 
không gian tên Bộ nạp{
 
/* chứa các đối tượng trình nạp lắp ráp, được lưu trữ trong một hàm băm
* và được khóa vào tệp .dll mà chúng đại diện. Mỗi trình nạp lắp ráp
* đối tượng có thể được tham chiếu theo tên/đường dẫn gốc và được sử dụng để
* tải các đối tượng, trả về dưới dạng kiểu Object. Tùy thuộc vào lớp gọi
* để chuyển đổi đối tượng sang kiểu cần thiết để sử dụng.
* Rất khuyến khích sử dụng giao diện ngoài!!
* */
công cộng lớp học ObjectLoader: IDisposable {
 
// về cơ bản tạo ra một thiết lập cặp băm song song
// một appDomain cho mỗi trình tải
được bảo vệ Tên miền có thể băm = mới Bảng băm();
// một trình tải cho mỗi DLL lắp ráp
được bảo vệ Bộ tải bảng băm = mới Bảng băm();
 
công cộng Trình tải đối tượng() { /*...*/ }
 
công cộng sự vật Lấy đối tượng( sợi dây Tên dll, sợi dây loạiTên, sự vật [] hàm tạoParms ){
Loader.AssemblyLoader al = vô giá trị ;
sự vật ồ = vô giá trị ;
thử {
al = (Loader.AssemblyLoader)loaders[dllName];
} nắm lấy (Ngoại lệ){}
nếu như (và == vô giá trị ){
Thiết lập AppDomainSetup = mới Cài đặt AppDomain();
thiết lập.ShadowCopyFiles = "ĐÚNG VẬY" ;
Tên miền AppDomain = AppDomain.CreateDomain(dllName, vô giá trị , cài đặt );
domains.Add(dllName, domain );
sự vật [] parms = {tên dll};
// đối tượng[] parms = null;
Liên kết BindingFlags = BindingFlags.CreateInstance | BindingFlags.Instance | BindingFlags.Public;
thử {
al = (Loader.AssemblyLoader)domain.CreateInstanceFromAndUnwrap(
"Loader.dll" , "Loader.AssemblyLoader" , ĐÚNG VẬY , ràng buộc, vô giá trị , parms, vô giá trị , vô giá trị , vô giá trị
);
} nắm lấy (Ngoại lệ){
ném mới Lỗi AssemblyLoadFailureException();
}
nếu như ( và != vô giá trị ){
nếu như ( !loaders.ContainsKey(dllName ) ){
loaders.Add(dllName, al);
} khác {
ném mới AssemblyAlreadyLoadedException();
}
} khác {
ném mới Lỗi AssemblyNotLoadedException();
}
}
nếu như ( và != vô giá trị ){
o = al. GetObject(kiểuTên, constructorParms);
nếu như ( hoặc != vô giá trị && hoặc AssemblyNotLoadedException (Lắp ráp không được tải)
ném mới Lỗi AssemblyNotLoadedException();
}
nếu như ( hoặc == vô giá trị || hoặc Ngoại lệ ObjectLoadFailure){
sợi dây tin nhắn = "Không thể tải đối tượng. Kiểm tra tên loại đó" + loạiTên +
" và các tham số của hàm tạo là chính xác. Đảm bảo rằng tên kiểu " + loạiTên +
" tồn tại trong hội đồng " + tên dll + "." ;
ném mới ObjectLoadFailureException(tin nhắn);
}
}
trở lại ôi;
}
 
công cộng vô hiệu Dỡ bỏ( sợi dây Tên dll){
nếu như (domain.ContainsKey(dllName) ){
Tên miền AppDomain = (AppDomain)domains[dllName];
AppDomain.Unload(tên miền);
tên miền.Xóa(dllName);
}
}
 
~Trình tải đối tượng(){
vứt bỏ( SAI );
}
 
công cộng vô hiệu Bỏ đi(){
vứt bỏ( ĐÚNG VẬY );
}
 
riêng tư vô hiệu vứt bỏ( bool xử lý){
nếu như ( xử lý ){
bộ nạp. Clear();
foreach ( sự vật ôi TRONG miền.Khóa){
sợi dây dllName = o.ToString();
Gỡ bỏ(dllName);
}
tên miền.Clear();
}
}
}
 
}

--- cắt cuối.

--- cắt tập tin lớp thứ hai.

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
hai mươi mốt
hai mươi hai
hai mươi ba
hai mươi bốn
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
sử dụng Hệ thống;
sử dụng Hệ thống.Phản chiếu;
 
không gian tên Bộ nạp {
// container để lắp ráp và hiển thị hàm GetObject
// để tạo một đối tượng bị ràng buộc muộn để ép kiểu bởi người tiêu dùng
// lớp này có nghĩa là được chứa trong một appDomain riêng biệt
// được điều khiển bởi lớp ObjectLoader để cho phép đóng gói đúng cách
// cho phép chức năng sao chép bóng phù hợp.
nội bộ lớp học AssemblyLoader: MarshalByRefObject, IDisposable {
 
#khu vực khai báo cấp lớp
riêng tư Lắp ráp a = vô giá trị ;
#khuvựccuối
 
#region các hàm tạo và hàm hủy
công cộng Lắp rápLoader sợi dây Đường dẫn đầy đủ){
nếu như ( một == vô giá trị ){
a = Assembly.LoadFrom(fullPath);
}
}
~Trình tải lắp ráp(){
vứt bỏ( SAI );
}
 
công cộng vô hiệu Bỏ đi(){
vứt bỏ( ĐÚNG VẬY );
}
 
riêng tư vô hiệu vứt bỏ( bool xử lý){
nếu như ( xử lý ){
một = vô giá trị ;
Hệ thống. GC. Thu thập();
Hệ thống.GC.WaitForPendingFinalizers();
Hệ thống.GC.Thu thập( 0 );
}
}
#khuvựccuối
 
#chức năng công cộng của vùng
công cộng sự vật Lấy đối tượng( sợi dây tên loại, sự vật []ctorParms){
Cờ BindingFlags = BindingFlags.CreateInstance | BindingFlags.Instance | BindingFlags.Public;
sự vật ồ = vô giá trị ;
nếu như ( một != vô giá trị ){
thử {
o = a.CreateInstance(kiểu tên, ĐÚNG VẬY , cờ, vô giá trị , ctorParms, vô giá trị , vô giá trị );
} nắm lấy (Ngoại lệ){
ồ = mới Ngoại lệ ObjectLoadFailure();
}
} khác {
ồ = mới Lỗi AssemblyNotLoadedException();
}
trở lại ôi;
}
công cộng sự vật Lấy đối tượng( sợi dây tên kiểu){
trở lại Lấy đối tượng(tên kiểu, vô giá trị );
}
#khuvựccuối
 
}
}

--- cắt cuối.

Một số tài nguyên liên quan: Tại sao không có phương thức Assembly.Unload? http://blogs.msdn.com/jasonz/archive/2004/05/31/145105.aspx .

AppDomains ("miền ứng dụng") http://blogs.msdn.com/cbrumme/archive/2003/06/01/51466.aspx .

AppDomain và Shadow Copy http://blogs.msdn.com/junfeng/archive/2004/02/09/69919.aspx .

Đây là phần cuối của bài viết này về giải thích chi tiết của C# về Assembly.Unload. Để biết thêm nội dung liên quan về C# về Assembly.Unload, vui lòng tìm kiếm các bài viết trước của tôi hoặc tiếp tục duyệt các bài viết liên quan sau. Tôi hy vọng bạn sẽ ủng hộ tôi trong tương lai! .

Liên kết gốc: https://www.cnblogs.com/ccBoy/archive/2004/07/13/23636.html.

Cuối cùng, bài viết này về giải thích chi tiết của C# về Assembly.Unload kết thúc tại đây. Nếu bạn muốn biết thêm về giải thích chi tiết của C# về Assembly.Unload, vui lòng tìm kiếm các bài viết CFSDN hoặc tiếp tục duyệt các bài viết liên quan. Tôi hy vọng bạn sẽ ủng hộ blog của tôi trong tương lai! .

36 4 0
qq735679552
Hồ sơ cá nhân

Tôi là một lập trình viên xuất sắc, rất giỏi!

Nhận phiếu giảm giá Didi Taxi miễn phí
Mã giảm giá Didi Taxi
Giấy chứng nhận ICP Bắc Kinh số 000000
Hợp tác quảng cáo: 1813099741@qq.com 6ren.com