我想知道,如果我有一个变量,例如一个字符串,如何将其值传递给我的新app域:
static string _str;
static void Main(string[] args) {
_str = "abc";
AppDomain domain = AppDomain.CreateDomain("Domain666");
domain.DoCallBack(MyNewAppDomainMethod);
AppDomain.Unload(domain);
Console.WriteLine("Finished");
Console.ReadKey();
}
static void MyNewAppDomainMethod() {
Console.WriteLine(_str); //want this to print "abc"
}
Run Code Online (Sandbox Code Playgroud)
谢谢
我大致了解AppDomain是什么,但我并不完全了解AppDomain的用途.
我参与了一个基于服务器的大型C#/ C++应用程序,我想知道如何使用AppDomains来提高稳定性/安全性/性能.
特别是:
当我AppDomain.CreateDomain在C#中创建一个新的AppDomain时,是否会在新创建的AppDomain中加载asseblies时调用静态构造函数?
有问题的程序集已加载到当前域中.
我想在appdomain中托管一个exe并为其分配CPU和内存上限,以便它不会使用超过指定的处理能力.这可能吗?怎么做?
我的应用程序需要将插件加载到单独的应用程序域中,然后异步执行其中的一些代码.我编写了一些代码来包装可Task编组类型:
static class RemoteTask
{
public static async Task<T> ClientComplete<T>(RemoteTask<T> remoteTask,
CancellationToken cancellationToken)
{
T result;
using (cancellationToken.Register(remoteTask.Cancel))
{
RemoteTaskCompletionSource<T> tcs = new RemoteTaskCompletionSource<T>();
remoteTask.Complete(tcs);
result = await tcs.Task;
}
await Task.Yield(); // HACK!!
return result;
}
public static RemoteTask<T> ServerStart<T>(Func<CancellationToken, Task<T>> func)
{
return new RemoteTask<T>(func);
}
}
class RemoteTask<T> : MarshalByRefObject
{
readonly CancellationTokenSource cts = new CancellationTokenSource();
readonly Task<T> task;
internal RemoteTask(Func<CancellationToken, Task<T>> starter)
{
this.task = starter(cts.Token);
}
internal void Complete(RemoteTaskCompletionSource<T> tcs)
{
task.ContinueWith(t …Run Code Online (Sandbox Code Playgroud) 我正在寻找有关.NET应用程序何时以及如何共享加载程序集的更多详细信息.我有兴趣在OS进程之间共享,也在同一进程内的AppDomains之间共享.共享程序集通过避免在内存中具有相同程序集的多个副本来减少系统内存使用量,我认为这是主要的好处,但有兴趣知道是否存在其他好处和/或影响.
到目前为止我学到的内容摘要......
Sysinternals进程资源管理器可用于列出.NET进程的AppDomain以及加载到每个AppDomain中的程序集.
.NET进程似乎总是将"核心"程序集加载到名为"SharedDomain"的AppDomain中(假设这在当前进程中的AppDomain之间共享是合理的).
任务管理器和Process Explorer报告"工作集共享"和"工作集可共享"的内存使用数量不是无关紧要,但不清楚共享的内容.(它是共享AppDomain中的'核心'程序集吗?其他[非核心]程序集是否也共享?
在一个简单的测试中,我推出了两个独立的.NET应用程序副本,并为每个应用程序附加了一个Visual Studio调试器."模块"视图显示已加载的程序集及其在内存中的地址.在我的测试用例中,每个加载的模块都位于两个进程中的相同地址.(这是否表示共享,或者这个虚拟地址空间是否必须共享?)
ASP.NET 4.5通过一个叫做装配实习机制支持组件的共享(见看在ASP.NET 4.5共享通用组件,分享共同组件,与aspnet_intern.exe共享通用组件).它似乎通过设置文件系统符号链接(符号链接)来工作,以便不同的Web应用程序指向共享bin文件夹,因此这就提出了一个问题,即ASP.NET是否只是使用符号链接来触发.NET中的标准程序集共享行为,或者是否有更具体的ASP.NET和IIS AppPools正在进行.
注意.在安装了Visual Studio 2013的计算机上,可以在以下位置找到aspnet_intern.exe:
C:\ Program Files(x86)\ Microsoft SDKs\Windows\v8.1A\bin\NETFX 4.5.1工具\
在更高版本的.NET和Windows Server中,ASP.NET启动时间和内存使用情况有了进一步的改进; 请参阅ASP.NET应用程序暂停 - 响应式共享.NET Web主机,.Net 4.5中的ASP.NET共享主机方案的性能改进,但我不确定这些更改与此问题的相关性如何.
ASP.NET程序集共享也包含在.NET 4.5简介中.
还想知道JITted代码是否共享,因为加载的程序集由MSIL,资源,元数据等组成,并且当代码被JIT时必须分配更多内存.
在紧凑框架中也有关于汇编共享的讨论(我们相信共享,MSDN博客,Abhinaba Basu)
--- UPDATE ---
我使用sysinternals VMMap工具来检查两个AppPools,一个用asp.net程序集internign设置,另一个没有.我还"触摸"了一个测试aspx页面,导致ASP.NET加载所有程序集(并且global.asax运行少量代码,因此导致一些JITting).
报告的两个AppPools的内存使用数据非常相似,工作集,WS Private和WS Shareable基本相同.但是,在"实习"AppPool中,WS Shared要大得多.这是意外的(对我来说),因为没有其他进程可以与之共享,但VMMap显示的是内存块(标记为'.text'并具有执行/读保护),这些内存块在实习AppPool中显示为共享内存,而另一个AppPool中的相同程序集不共享.我对此的解释是,进程中的虚拟内存块被映射到同一物理内存,然后报告为"WS Shared".
ASLR
关于装配空间布局随机化.VMMap工具显示许多类型为"Image(ASLR)"的内存块.ASLR随机化了内存中程序集的位置以阻止恶意软件,我想知道这是否会阻止程序集实习工作正常.使用EMET工具禁用机器的ASLR 会导致程序集地址更加规则,但不会更改报告的内存数,因此它似乎不会影响程序集实习.值得注意的是VMMap仍然显示带有'ASLR'的图像,我怀疑这只是意味着装配/图像被标记为支持/允许ASLR,而不是ASLR生效.
这本来是一个更冗长的问题,但现在我构建了一个较小的可用示例代码,因此原始文本不再相关.
我有两个项目,一个包含一个没有成员的结构,名为TestType.该项目由主项目引用,但程序集不包含在可执行文件目录中.主项目创建一个新的app-domain,它使用所包含程序集的名称注册AssemblyResolve事件.在主app-domain中,处理相同的事件,但它手动从项目资源加载程序集.
然后新的app-domain构建自己的TestType版本,但字段多于原始字段.主app-domain使用虚拟版本,新app-domain使用生成的版本.
当调用 在其签名中具有TestType的方法时(即使只是简单地返回它就足够了),它似乎只会使运行时不稳定并破坏内存.
我使用的是.NET 4.5,在x86下运行.
DummyAssembly:
using System;
[Serializable]
public struct TestType
{
}
Run Code Online (Sandbox Code Playgroud)
主要项目:
using System;
using System.Reflection;
using System.Reflection.Emit;
internal sealed class Program
{
[STAThread]
private static void Main(string[] args)
{
Assembly assemblyCache = null;
AppDomain.CurrentDomain.AssemblyResolve += delegate(object sender, ResolveEventArgs rargs)
{
var name = new AssemblyName(rargs.Name);
if(name.Name == "DummyAssembly")
{
return assemblyCache ?? (assemblyCache = TypeSupport.LoadDummyAssembly(name.Name));
}
return null; …Run Code Online (Sandbox Code Playgroud) 基于我的所有阅读,应该有一个GC线程来调用所有终结器.现在,问题是这个"一个"线程的范围是什么 - 每个进程或每个应用程序域,因为域的整个意图是在一个进程空间中分离并创建"独立"的不同应用程序.
我在这里读到:
如果在终结器中发生未处理的异常,则CLR的执行线程将吞下该异常,将终结器视为正常完成,将其从可释放队列中移除并移至下一个条目.
更严重的是,如果你的终结器由于某种原因没有退出会发生什么,例如它会阻塞,等待一个永远不会发生的情况.在这种情况下,终结器线程将被挂起,因此不再有可终结的对象将被垃圾收集.您应该非常了解这种情况,并坚持编写最简单的代码来释放终结器中的非托管资源.
另一个考虑因素是应用程序关闭期间发生 当程序关闭时,垃圾收集器将尽力调用所有可终结对象的终结器,但有一些限制:
在关闭期间,可终结对象不会升级到更高的堆生成.
任何单个终结器最多只能执行2秒; 如果它需要更长时间,它将被杀死.
所有终结器的执行时间最长为40秒; 如果任何终结器仍在执行,或者此时待决,整个过程将被突然终止.
太多帖子(甚至官方文档)滥用术语"应用程序","进程"和"应用程序域" - 他们中的大多数甚至假设它们是相同的,因为通常应用程序在单个进程中在单个应用程序域中运行.这种滥用使得所有这些文档难以阅读,甚至没有用处.
因此,我的问题假设多个应用程序,每个应用程序在单个进程中在单独的应用程序域中运行.
所有这些应用程序是否共享相同的GC和终结器线程?上面的文章中描述的问题(挂起终结器线程)是否会影响该进程中的所有应用程序?如果是 - 是否有解决方法(除了不使用不良应用程序),就像以某种方式发现终结器线程并发送它Thread.Abort?
以上都是因为我遇到了类似的问题.我的应用程序在单独的应用程序域中运行,作为第三方软件(Outlook)的插件.由于各种原因,我需要调用GC.Collect和GC.WaitForPendingFinalizers来完全释放COM引用(对于Office/Outlook,通常的互操作例程是不够的),当一个特定的其他第三方插件运行时,我的GC.WaitForPendingFinalizers将永远挂起,所以我怀疑第三方添加的"坏"终结器.我无法控制替换/删除添加(客户端的要求),因此我必须自己弄清楚如何使它们共存.
我有一个命令对象,根据请求队列的请求进行工作.此特定命令将在子appdomain中执行其工作.在子appdomain中完成其工作的一部分涉及阻止ConcurrentQueue操作(例如,Add或Take).我需要能够通过请求队列传播中止信号,传递到子appdomain,并唤醒其中的工作线程.
因此,我认为我需要在AppDomain边界传递CancellationToken.
我尝试创建一个继承自MarshalByRefObject的类:
protected class InterAppDomainAbort : MarshalByRefObject, IAbortControl
{
public InterAppDomainAbort(CancellationToken t)
{
Token = t;
}
[SecurityPermissionAttribute(SecurityAction.Demand, Flags = SecurityPermissionFlag.Infrastructure)]
public override object InitializeLifetimeService()
{
return null;
}
public CancellationToken Token
{
get;
private set;
}
};
Run Code Online (Sandbox Code Playgroud)
并将此作为参数传递给worker函数:
// cts is an instance variable which can be triggered by another thread in parent appdomain
cts = new CancellationTokenSource();
InterAppDomainAbort abortFlag = new InterAppDomainAbort(cts.Token);
objectInRemoteAppDomain = childDomain.CreateInstanceAndUnwrap(...);
// this call will block for a long while the work is …Run Code Online (Sandbox Code Playgroud) 我无法将App.Config文件加载到App域中.
我正在使用
[System.AppDomain]::CurrentDomain.SetData("APP_CONFIG_FILE", $config_path)
Run Code Online (Sandbox Code Playgroud)
来自Powershell使用App.config调用.NET程序集,但仍未加载App.Config文件.
我也尝试重置缓存,如使用CurrentDomain.SetData("APP_CONFIG_FILE")中所述,在PowerShell ISE中不起作用.
这是我的测试脚本:
$configFile = "{ActualPhysicalPath}\App.Config"
gc $configFile
Add-Type -AssemblyName System.Configuration
[Configuration.ConfigurationManager].GetField("s_initState", "NonPublic, Static").SetValue($null, 0)
[Configuration.ConfigurationManager].GetField("s_configSystem", "NonPublic, Static").SetValue($null, $null)
([Configuration.ConfigurationManager].Assembly.GetTypes() | where {$_.FullName -eq "System.Configuration.ClientConfigPaths"})[0].GetField("s_current", "NonPublic, Static").SetValue($null, $null)
[Configuration.ConfigurationManager]::ConnectionStrings[0].Name
[System.AppDomain]::CurrentDomain.SetData("APP_CONFIG_FILE", $null)
[Configuration.ConfigurationManager]::ConnectionStrings[0].Name
[System.AppDomain]::CurrentDomain.SetData("APP_CONFIG_FILE", $configFile)
[Configuration.ConfigurationManager]::ConnectionStrings[0].Name
Run Code Online (Sandbox Code Playgroud)
我总是得到存储在machine.config中的连接字符串,而不是App.config中的连接字符串.
如何在应用程序域中加载我的特定App.Config文件?