16

首先,问题是:CLR 规范是否保证在同一进程内的多个应用程序域中执行的代码将共享相同的地址空间?通过“共享地址空间”,我的意思是指向在某个应用程序域中分配的内存的指针对于在同一进程内托管的所有应用程序域进行读写都是有效的。

考虑这个说明问题的独立示例:程序Worker在单独的应用程序域中分配一个对象。为 10,000个Worker整数分配一个内存块,并用数据填充它。然后程序跨应用程序域边界调用以获取指向已分配块的指针,并验证它是否可以读取 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
                    );
                }
            }
        }
    }
}

我跑了很多次,每次都有效。直觉上它应该可以工作:毕竟,应用程序域在一个进程中,所以它们必须共享相同的虚拟地址空间。但是,这感觉就像是在利用 Microsoft 可能随时取消的功能。CLR 的规范中是否有某些内容确认或否认此技巧的合法性?


如果您想知道我为什么要问这样一个奇怪的问题,我正在寻找一种跨应用程序域边界传递大量(以千兆字节为单位)数据的方法,同时在空间和时间上都具有最小的开销。如果我能证明它的合法性,这将是我理想的解决方案。

4

2 回答 2

1

看看:任何人都可以解释 MarshalByRefObject 的主要用途。在您的场景中,您只传递了一个代理而不是实际的对象,并且没有复制内存。

编辑:

  1. “合法性”!=“技巧”,您的黑客通过不编组对另一个 AppDomain 中的数据的调用来破坏 AppDomains。运行时容器可能会设置/更改可能会破坏您的应用程序的安全限制,例如它是否在 IIS 中运行?(在您的情况下,您访问的不是对象而是内存,因此它可能“还不错”。)这是您在客户站点上部署的产品吗?
  2. 我认为通过代理进行封送处理存在性能问题,因此您求助于 IntPtr(去掉中间人)
  3. 各种“工人”AppDomain 是否在操纵 blob?如果是这样,我会担心最终内存会被破坏......因为你没有编组你的电话。
  4. 这是在 C# 中创建的非托管内存。如果实际上,blob 是由非托管 DLL 分配的,那么您必须确保未卸载非托管 DLL。同样,如果要部署到 IIS,那么您无法控制 AppDomain 的生命周期,而 IIS 可以。这将打破你的黑客。
  5. 是的,虚拟内存是每个进程而不是每个 AppDomain,因此所有 AppDomain 共享相同的虚拟地址空间。
  6. 不管我有什么保留,这很酷:)
于 2013-10-14T13:58:40.293 回答
-1

我没有直接的答案给你。MarshalByRefObject 的存在可能表明使用了公共地址空间,但可能没有。

您还可以查看内存映射文件

于 2012-08-20T20:47:38.000 回答