AppDomain 地址空间
Posted
技术标签:
【中文标题】AppDomain 地址空间【英文标题】:AppDomain address space 【发布时间】:2012-08-16 04:41:53 【问题描述】:首先,问题是:CLR 规范是否保证在同一进程内的多个应用程序域中执行的代码将共享相同的地址空间? “共享地址空间”是指指向在某个应用程序域中分配的内存的指针对于在同一进程内托管的所有应用程序域进行读写都是有效的。
考虑这个说明问题的自包含示例:程序在单独的应用程序域中分配一个Worker
对象。 Worker
为 10,000 个整数分配一个内存块,并用数据填充它。然后程序跨应用程序域边界调用以获取指向已分配块的指针,并验证它是否可以读取 10,000 项中的每一项。
using System;
using System.Reflection;
using System.Runtime.InteropServices;
namespace crossapp
public class Worker : MarshalByRefObject
private readonly IntPtr myData;
public const int DataLength = 10000;
public Worker()
Console.Error.WriteLine(
"Memory allocation happens in app domain '0'"
, Assembly.GetExecutingAssembly().FullName
);
myData = Marshal.AllocHGlobal(sizeof(int) * DataLength);
unsafe
var ptr = (int*) myData.ToPointer();
for (var i = 0 ; i != DataLength ; i++)
ptr[i] = 2*i + 1;
public IntPtr GetData()
return myData;
class Program
static void Main()
var ad = AppDomain.CreateDomain("New domain");
var wrk = (Worker)ad.CreateInstanceAndUnwrap(
Assembly.GetExecutingAssembly().FullName
, "crossapp.Worker"
);
var data = wrk.GetData();
var badCount = 0;
unsafe
var ptr = (int*)data.ToPointer();
for (var i = 0 ; i != Worker.DataLength ; i++)
var expect = 2*i + 1;
if (ptr[i] != expect)
Console.Error.WriteLine(
"Mismatch in position 0: 1 != 2"
, i, expect, ptr[i]
);
badCount++;
if (badCount == 0)
Console.Error.WriteLine(
"All 0 items have matched."
, Worker.DataLength
);
else
Console.Error.WriteLine(
"Found 0 mismatches out of 1."
, badCount
, Worker.DataLength
);
我运行了很多次,每次都有效。直觉上它应该可以工作:毕竟,应用程序域在一个进程中,所以它们必须共享相同的虚拟地址空间。但是,这感觉像是利用了微软可能随时取消的功能。 CLR 的规范中是否有某些内容确认或否认此技巧的合法性?
如果您想知道我为什么要问这样一个奇怪的问题,我正在寻找一种跨应用程序域边界传递大量(以千兆字节为单位)数据的方法,同时在空间和时间上的开销最小。如果我能证明它的合法性,这将是我理想的解决方案。
【问题讨论】:
Marshal.AllocHGlobal doco 读取:从进程的非托管内存中分配内存。这似乎表明您以这种方式创建的指针是跨应用程序域安全的,只要应用程序域存在于同一进程中。 @downvoter 这个问题有什么问题来赢得反对票? 【参考方案1】:请看:Anyone can explain the major use of MarshalByRefObject。 在您的场景中,您只传递了一个代理而不是实际的对象,并且没有复制内存。
编辑:
-
"legitimacy" != "trick",你的 hack 正在破坏 AppDomains,因为它没有编组对另一个 AppDomain 中数据的调用。运行时容器可能会设置/更改可能会破坏您的应用程序的安全限制,例如这是在 IIS 中运行的吗? (在您的情况下,您访问的不是对象而是内存,所以它可能“还不错”。)这是您在客户站点部署的产品吗?
我认为通过代理进行封送处理存在性能问题,因此您求助于 IntPtr(去掉中间人)
各种“工人”AppDomain 是否在操纵 blob?如果是这样,我会担心最终内存会被破坏......因为你没有编组你的调用。
这是在 C# 中创建的非托管内存。如果实际上,blob 是由非托管 DLL 分配的,那么您必须确保未卸载非托管 DLL。同样,如果要部署到 IIS,那么您无法控制 AppDomain 的生命周期,而 IIS 可以。这将打破你的黑客。
是的,虚拟内存是每个进程而不是每个 AppDomain,因此所有 AppDomain 共享相同的虚拟地址空间。
不管我有什么保留,这很酷:)
【讨论】:
我没有建议将或应该复制内存。我正在传回一个指针,它就像指向同一个内存一样工作。我的问题是,标准中是否有一部分可以保证会发生这种情况? 你不是在传递一个“指针”,你是在传递一个代理。它看起来很像 CORBA“模型”:您正在传递一个将命令编组到另一个 AppDomain 中的对象的代理。 通过调用(确实使用代理)传递的是一个普通指针。查看第二个unsafe
块的第一行,看看它是如何使用的。使用代理传递指针这一事实并不重要:一旦传递了指针,我就通过该指针访问剩余的数据,绕过代理,它就可以工作了。我正在寻找证明这不是巧合的证据。【参考方案2】:
我没有直接的答案。 MarshalByRefObject 的存在可能表明使用了公共地址空间,但可能没有。
你也可以看看memory-mapped files
【讨论】:
MarshalByRefObject
的文档在某些时候说“对象的成员在创建它们的应用程序域之外不可用”,并且还说它们返回“代理” .这向我表明,微软要么做一些非平凡的映射,要么保留在未来做一些非平凡的映射的权利。至于内存映射文件,它们比“普通”内存要重,因为它们必须跨进程边界工作。最重要的是,没有文件:我需要传递指向瞬态数据块的指针。
我没有阅读那部分文档。至于内存映射文件,我想你可以先固定内存,然后将指针写入 mmf。但进一步考虑,您可以只固定内存,然后使用现有的指针传递函数。以上是关于AppDomain 地址空间的主要内容,如果未能解决你的问题,请参考以下文章
内核逻辑地址空间、内核虚拟地址空间和用户虚拟地址空间有啥区别?