AppDomain address space

2019-03-15 01:19发布

问题:

First, the question: do CLR specifications guarantee that the code executing in multiple app domains within the same process will share the same address space? By "sharing the address space" I mean that pointers to memory allocated in one of the app domains will be valid for reading and writing across all app domains hosted inside the same process.

Consider this self-contained example illustrating the question: the program allocates a Worker object in a separate app domain. The Worker allocates a memory block for 10,000 integers, and fills it in with data. The program then calls across the app domain boundary to obtain the pointer to the allocated block, and verifies that it can read every one of the 10,000 items.

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
                    );
                }
            }
        }
    }
}

I ran this many times, and it worked every single time. Intuitively it should work: after all, app domains are within a single process, so they must share the same virtual address space. However, this feels like an exploit of a feature that Microsoft may take away at any time. Is there something in the specification of CLR that confirms or denies legitimacy of this trick?


In case you are wondering why I am asking such a strange question, I am looking for a way of passing large (in gigabytes) amounts of data across app domain boundary, with minimal overhead in both space and time. This would be my ideal solution if I could prove its legitimacy.

回答1:

Look at: Anyone can explain the major use of MarshalByRefObject . In your scenario, you are only passing a proxy and not the actual object and the memory is not being copied.

EDIT:

  1. "legitimacy" != "trick", your hack is undermining AppDomains by not marshaling calls to data in another AppDomain. The run-time container may set/change security limitations which might break your app, e.g. is this running inside IIS? (In your case, you are not accessing an object but memory, so it is perhaps "not so bad".) Is this a product your are deploying at a customer's site?
  2. I assume that there was a performance problem with marshaling via proxy, so you resorted to IntPtr (cut out the middle man)
  3. Are the various "worker" AppDomains manipulating the blob? If so, I would be concerned that eventually the memory would be corrupted... because you are not marshaling your calls.
  4. This is unmanaged memory created in C#. If in reality, the blob is allocated by an unmanaged DLL, then you must ensure that the unmanaged DLL is not unloaded. Again, if are deploying to IIS, then you don't control your AppDomains' lifecycles, IIS does. This will break your hack.
  5. Yes, virtual memory is per process and not per AppDomain, so all AppDomain share the same virtual address space.
  6. Regardless of my reservations, it is very cool :)


回答2:

I have no direct answer for you. The existance of MarshalByRefObject might indicate that a common address space is used, but perhaps not.

You might also look into memory-mapped files