- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章C# 有关Assembly.Unload详解由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
CLR 产品单元经理(Unit Manager) Jason Zander 在前几天一篇文章 Why isn't there an Assembly.Unload method? 中解释了为什么 CLR 中目前没有实现类似 Win32 API 中 UnloadLibrary 函数功能的 Assembly.Unload 方法。 他认为之所以要实现 Assembly.Unload 函数,主要是为了回收空间和更新版本两类需求。前者在使用完 Assembly 后回收其占用资源,后者则卸载当前版本载入更新的版本。例如 ASP.NET 中对页面用到的 Assembly 程序的动态更新就是一个很好的使用示例。但如果提供了 Assembly.Unload 函数会引发一些问题:
1.为了包装 CLR 中代码所引用的代码地址都是有效的,必须跟踪诸如 GC 对象和 COM CCW 之类的特殊应用。否则会出现 Unload 一个 Assembly 后,还有 CLR 对象或 COM 组件使用到这个 Assembly 的代码或数据地址,进而导致访问异常。而为了避免这种错误进行的跟踪,目前是在 AppDomain 一级进行的,如果要加入 Assembly.Unload 支持,则跟踪的粒度必须降到 Assembly 一级,这虽然在技术上不是不能实现,但代价太大了.
2.如果支持 Assembly.Unload 则必须跟踪每个 Assembly 的代码使用到的句柄和对现有托管代码的引用。例如现在 JITer 在编译方法时,生成代码都在一个统一的区域,如果要支持卸载 Assembly 则必须对每个 Assembly 都进行独立编译。此外还有一些类似的资源使用问题,如果要分离跟踪技术上虽然可行,但代价较大,特别是在诸如 WinCE 这类资源有限的系统上问题比较明显.
3.CLR 中支持跨 AppDomain 的 Assembly 载入优化,也就是 domain neutral 的优化,使得多个 AppDomain 可以共享一份代码,加快载入速度。而目前 v1.0 和 v1.1 无法处理卸载 domain neutral 类型代码。这也导致实现 Assembly.Unload 完整语义的困难性.
基于上述问题, Jason Zander 推荐使用其他的设计方法来回避对此功能的使用。如 Junfeng Zhang 在其 BLog 上介绍的 AppDomain and Shadow Copy,就是 ASP.NET 解决类似问题的方法.
在构造 AppDomain 时,通过 AppDomain.CreateDomain 方法的 AppDomainSetup 参数中 AppDomainSetup.ShadowCopyFiles 设置为 "true" 启用 ShadowCopy 策略;然后设置 AppDomainSetup.ShadowCopyDirectories 为复制目标目录;设置 AppDomainSetup.CachePath + AppDomainSetup.ApplicationName 指定缓存路径和文件名。 通过这种方法可以模拟 Assembly.Unload 的语义。实现上是将需要管理的 Assembly 载入到一个动态建立的 AppDomain 中,然后通过跨 AppDomain 的透明代理调用其功能,使用 AppDomain.Unload 实现 Assembly.Unload 语义的模拟。chornbe 给出了一个简单的包装类,具体代码见文章末尾.
这样做虽然在语义上能够基本上模拟,但存在很多问题和代价:
1.性能:在 CLR 中,AppDomain 是类似操作系统进程的逻辑概念,跨 AppDomain 通讯就跟以前跨进程通讯一样受到诸多限制。虽然通过透明代理对象能够实现类似跨进程 COM 对象调用的功能,自动完成参数的 Marshaling 操作,但必须付出相当的代价。Dejan Jelovic给出的例子(Cross-AppDomain Calls are Extremely Slow)中,P4 1.7G 下只使用内建类型的调用大概需要 1ms。这对于某些需要被频繁调用的函数来说代价实在太大了。如他提到实现一个绘图的插件,在 OnPaint 里面画 200 个点需要 200ms 的调用代价。虽然可以通过批量调用进行优化,但跨 AppDomain 调用效率的惩罚是肯定无法逃脱的。好在据说 Whidbey 中,对跨 AppDomain 调用中的内建类型,可以做不 Marshal 的优化,以至于达到比现有实现调用速度快 7 倍以上,...,我不知道该夸奖 Whidbey 实现的好呢,还是痛骂现有版本之烂,呵呵 。
2.易用性:需要单独卸载的 Assembly 中类型可能不支持 Marshal,此时就需要自行处理类型的管理.
3.版本:在多个 AppDomain 中如何包装版本载入的正确性.
此外还有安全方面问题。对普通的 Assembly.Load 来说,载入的 Assembly 是运行在载入者的 evidence 下,而这绝对是一个安全隐患,可能遭受类似 unix 下面通过溢出以 root 权限读写文件的程序来改写系统文件的类似攻击。而单独在一个 AppDomain 中载入 Assembly 就能够单独设置 CAS 权限,降低执行权限。因为 CLR 架构下的四级权限控制机制,最细的粒度只能到 AppDomain。好在据说 Whidbey 会加入对使用不同 evidence 载入 Assembly 的支持.
通过这些讨论可以看到,Assembly.Unload 对于基于插件模型的程序来说,其语义的存在是很重要的。但在目前和近几个版本来说,通过 AppDomain 来模拟其语义是比较合适的选择,虽然要付出性能和易用性的问题,但能够更大程度上控制功能和安全性等方面因素。长远来说,Assembly.Unload 的实现是完全可行的,Java 中对类的卸载就是最好的例子,前面那些理由实际上都是工作量和复杂度方面的问题,并不存在无法解决的技术问题.
You must also encapsulate the loaded assembly into another class, which is loaded by the new appdomain. Here's the code as it's working for me: (I've created a few custom exception types, and you'll notice I had them back - they're not descended from MarshalByRefObject so I can't just throw them from the encapsulated code) 。
--- cut first class file 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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
|
using
System;
using
System.Reflection;
using
System.Collections;
namespace
Loader{
/* contains assembly loader objects, stored in a hash
* and keyed on the .dll file they represent. Each assembly loader
* object can be referenced by the original name/path and is used to
* load objects, returned as type Object. It is up to the calling class
* to cast the object to the necessary type for consumption.
* External interfaces are highly recommended!!
* */
public
class
ObjectLoader : IDisposable {
// essentially creates a parallel-hash pair setup
// one appDomain per loader
protected
Hashtable domains =
new
Hashtable();
// one loader per assembly DLL
protected
Hashtable loaders =
new
Hashtable();
public
ObjectLoader() {
/*...*/
}
public
object
GetObject(
string
dllName,
string
typeName,
object
[] constructorParms ){
Loader.AssemblyLoader al =
null
;
object
o =
null
;
try
{
al = (Loader.AssemblyLoader)loaders[ dllName ];
}
catch
(Exception){}
if
( al ==
null
){
AppDomainSetup setup =
new
AppDomainSetup();
setup.ShadowCopyFiles =
"true"
;
AppDomain domain = AppDomain.CreateDomain( dllName,
null
, setup );
domains.Add( dllName, domain );
object
[] parms = { dllName };
// object[] parms = null;
BindingFlags bindings = BindingFlags.CreateInstance | BindingFlags.Instance | BindingFlags.Public;
try
{
al = (Loader.AssemblyLoader)domain.CreateInstanceFromAndUnwrap(
"Loader.dll"
,
"Loader.AssemblyLoader"
,
true
, bindings,
null
, parms,
null
,
null
,
null
);
}
catch
(Exception){
throw
new
AssemblyLoadFailureException();
}
if
( al !=
null
){
if
( !loaders.ContainsKey( dllName ) ){
loaders.Add( dllName, al );
}
else
{
throw
new
AssemblyAlreadyLoadedException();
}
}
else
{
throw
new
AssemblyNotLoadedException();
}
}
if
( al !=
null
){
o = al.GetObject( typeName, constructorParms );
if
( o !=
null
&& o
is
AssemblyNotLoadedException ){
throw
new
AssemblyNotLoadedException();
}
if
( o ==
null
|| o
is
ObjectLoadFailureException ){
string
msg =
"Object could not be loaded. Check that type name "
+ typeName +
" and constructor parameters are correct. Ensure that type name "
+ typeName +
" exists in the assembly "
+ dllName +
"."
;
throw
new
ObjectLoadFailureException( msg );
}
}
return
o;
}
public
void
Unload(
string
dllName ){
if
( domains.ContainsKey( dllName ) ){
AppDomain domain = (AppDomain)domains[ dllName ];
AppDomain.Unload( domain );
domains.Remove( dllName );
}
}
~ObjectLoader(){
dispose(
false
);
}
public
void
Dispose(){
dispose(
true
);
}
private
void
dispose(
bool
disposing ){
if
( disposing ){
loaders.Clear();
foreach
(
object
o
in
domains.Keys ){
string
dllName = o.ToString();
Unload( dllName );
}
domains.Clear();
}
}
}
}
|
--- end cut 。
--- cut second class file 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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
|
using
System;
using
System.Reflection;
namespace
Loader {
// container for assembly and exposes a GetObject function
// to create a late-bound object for casting by the consumer
// this class is meant to be contained in a separate appDomain
// controlled by ObjectLoader class to allow for proper encapsulation
// which enables proper shadow-copying functionality.
internal
class
AssemblyLoader : MarshalByRefObject, IDisposable {
#region class-level declarations
private
Assembly a =
null
;
#endregion
#region constructors and destructors
public
AssemblyLoader(
string
fullPath ){
if
( a ==
null
){
a = Assembly.LoadFrom( fullPath );
}
}
~AssemblyLoader(){
dispose(
false
);
}
public
void
Dispose(){
dispose(
true
);
}
private
void
dispose(
bool
disposing ){
if
( disposing ){
a =
null
;
System.GC.Collect();
System.GC.WaitForPendingFinalizers();
System.GC.Collect( 0 );
}
}
#endregion
#region public functionality
public
object
GetObject(
string
typename,
object
[] ctorParms ){
BindingFlags flags = BindingFlags.CreateInstance | BindingFlags.Instance | BindingFlags.Public;
object
o =
null
;
if
( a !=
null
){
try
{
o = a.CreateInstance( typename,
true
, flags,
null
, ctorParms,
null
,
null
);
}
catch
(Exception){
o =
new
ObjectLoadFailureException();
}
}
else
{
o =
new
AssemblyNotLoadedException();
}
return
o;
}
public
object
GetObject(
string
typename ){
return
GetObject( typename,
null
);
}
#endregion
}
}
|
--- end cut 。
相关的一些资源: Why isn't there an Assembly.Unload method? http://blogs.msdn.com/jasonz/archive/2004/05/31/145105.aspx 。
AppDomains ("application domains") http://blogs.msdn.com/cbrumme/archive/2003/06/01/51466.aspx 。
AppDomain and Shadow Copy http://blogs.msdn.com/junfeng/archive/2004/02/09/69919.aspx 。
到此这篇关于C# 有关Assembly.Unload详解的文章就介绍到这了,更多相关C# 有关Assembly.Unload内容请搜索我以前的文章或继续浏览下面的相关文章希望大家以后多多支持我! 。
原文链接:https://www.cnblogs.com/ccBoy/archive/2004/07/13/23636.html 。
最后此篇关于C# 有关Assembly.Unload详解的文章就讲到这里了,如果你想了解更多关于C# 有关Assembly.Unload详解的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
----- 简而言之----- 我有一个文件,比如x.html,它加载到其他文件的一些div中(使用函数jquery.load)。 但是x.html需要知道是否在您的位置加载了另一个html。 那么,
美好的一天, 我有java web应用程序,我会在登录后执行类似以下操作: 登录后,系统将显示登陆页面,在登陆页面中,会有一个选项卡菜单,并且选项卡菜单中有许多模块可以触发以导航到不同的页面。 我需要
这个问题在这里已经有了答案: 9年前关闭。 Possible Duplicate: how to delete the pluginassembly after AppDomain.Unload(do
我想在用户使用 jQuery 放弃特定页面时执行操作方法。 该页面有以下代码: $(window).unload(function () { aler
我加载了两个模块(NecessaryModule1.hs 和 NecessaryModule2.hs,如 Haskell : loading ALL files in current director
当用户单击提交按钮并执行操作时,我需要使用 VBA 关闭 Excel 用户窗体。 如何关闭用户表单本身? 我已经尝试过此操作,但它返回 361 错误。 Unload Me 最佳答案 正如最上面的答案所
我尝试运行以下查询以从 Redshift 卸载到 S3,但收到无益的错误。我们尝试转义所有可能导致问题的字符,并传入参数(包装程序是Python): unload ('select
我无法在 SO 上找到使用 Java VM (JVM) 参数来记录类卸载的 Web 搜索工作方式。 这里http://www.herongyang.com/JVM/ClassLoader-JVM-Op
我正在使用 NodeJS-ReactJS 同构应用程序,当我单击 Link 时,我收到一条错误消息 未捕获( promise )错误:请求已终止 可能原因:网络不在线、Access-Control-A
我有以下代码: D $(window).unload( function () { alert("Bye now!"); } );
我正在阅读 jQuery API Documentation 中给出的函数 .unload() 的 jQuery 文档。 上面写得很清楚,.unload()将在1.8之后的版本中被弃用,并在3.x中被
我们一直遇到一个奇怪的问题,我不确定如何解决,我认为这可能与最近的 Google Chrome 更新有关,但我想要一些方法在错误跟踪器上打开问题之前检查自己的健全性。 问题 我们有一个内部网络应用程序
我正在使用 PHP + MySQL + JavaScript 制作一个小型聊天应用程序,我编写了一个函数 disonnectUser(),当用户按下断开连接按钮时调用该函数。在这里: function
我继承了一个 web 框架,以前的开发人员在页面生命周期的 init/unload 方法中打开和关闭了他的数据库连接。构造函数本质上是这样的(为了说明重点而简化); public class Base
我需要在 c#/.net 中实现一个插件架构以便加载 自定义用户定义的操作 自定义数据网格的数据类型处理代码/转换/... 来自非静态链接程序集文件。 因为应用程序必须处理许多自定义用户定义的操作,所
XNA 游戏有一个 Unload() 方法,其中的内容应该被卸载。但这有什么意义呢?如果正在卸载所有内容,那么游戏肯定正在退出,在这种情况下所有内容都会被垃圾收集,对吧? 最佳答案 据我所知,它对任何
根据多种资源(例如,通过 C# 的 MSDN 和 CLR),当我们调用 AppDomain.Unload(userDomain) 时,userDomain 中的线程将被强制抛出 ThreadAbort
到目前为止的故事是这样的,我有一个使用 AppDomain 来执行某些任务的 worker thingy。该域的设置和拆卸成本很高。所以我为工作人员创建了一个 WeakReference 对象的每个线
我正在尝试在卸载页面之前向服务器发帖,然后我关注了 this它工作正常。我的问题是 window.unload 上的 $.post 在它卸载后 被触发。我尝试使用注销链接并检查我的日志,我得到以下信息
任何人都可以解释为什么下面的行会在运行时出现在输出控制台中? (一个可能的答案是完全 permGen,但这可以排除,因为该程序仅使用 PermGen 中可用的 max100MB 中的 24MB) [卸
我是一名优秀的程序员,十分优秀!