none
Use unmanaged buffer for an array RRS feed

  • Question

  • I would like to be able to allocate an array of value types in unmanaged memory.

    The reason that I want to do this is that the array needs to be allocated on page-locked memory.

    Obviously it would be "unsafe" to say the least, and the garbage collector would have an issue dealing with this, but I figure that as long as the array elements do no reference any objects, the GC could just leave the array alone.

    I have experimented with cheating the CLR with the code below by copying the 12 byte array header into unmanaged memory (32 bit clr), but when inspecting the resulting array a, visual studio says that it does not really exist. Attempting to assign to index 0 sometimes works and sometimes throws an IndexOutOfRangeException - probably because of GC somehow, but I'm not allowed to pin doubleArray and tempateArray.


    1 int[][] doubleArray = new int[1][];  
    2 int[] templateArray = new int[1];  
    3  
    4 GC.Collect();  
    5  
    6 IntPtr arrayPtrAddress = Marshal.UnsafeAddrOfPinnedArrayElement(doubleArray, 0);  
    7 IntPtr mem = Marshal.AllocHGlobal(400);  
    8 IntPtr arrayStartAddress = (IntPtr) ((int)mem + 12);  
    9  
    10 int* metadataSrc = (int*) Marshal.UnsafeAddrOfPinnedArrayElement(templateArray, 0);  
    11 int* metadataDest = (int*) arrayStartAddress;  
    12 metadataDest[-3] = metadataSrc[-3];  
    13 metadataDest[-2] = metadataSrc[-2];  
    14 metadataDest[-1] = metadataSrc[-1];  
    15  
    16 Marshal.WriteIntPtr(arrayPtrAddress, arrayStartAddress);  
    17 var a = doubleArray[0];  
    18  
    19 a[0] = 234;  
    20 int j = a[0];  
    21 a.Length.ToString();  
    22  

    Another option would be to host the CLR, but I would really like to avoid that.

    Any good ideas?


    Thanks,
    Rasmus
    Thursday, September 11, 2008 11:03 PM

Answers

  • You are using UnsafeAddressOfPinnedArrayElement() but your forgot to pin the array.  Use GCHandle to pin it.  If you have to pin it for a long time, be sure to use a large array (> 85 KB) so it gets allocated in the large object heap and can't clog up the garbage collector.
    Hans Passant.
    • Marked as answer by Zhi-Xin Ye Thursday, September 18, 2008 12:46 PM
    Friday, September 12, 2008 3:00 AM
    Moderator

All replies

  • AFAIK, CLR has no support for what is referred to in C++ as "placement new".

    When you allocate objects, it is not possible to specify where in memory they are placed.

    As I think you know, you can pin them in the place where they are located and then access them directly via unmanaged code at the location the CLR tells you.  The CLR picks the location -- not you.

    Friday, September 12, 2008 12:12 AM
  • You are using UnsafeAddressOfPinnedArrayElement() but your forgot to pin the array.  Use GCHandle to pin it.  If you have to pin it for a long time, be sure to use a large array (> 85 KB) so it gets allocated in the large object heap and can't clog up the garbage collector.
    Hans Passant.
    • Marked as answer by Zhi-Xin Ye Thursday, September 18, 2008 12:46 PM
    Friday, September 12, 2008 3:00 AM
    Moderator
  • True, but it is not possible to pin an array containing reference types - even GCHandle throws an exception. That is the reason for the GC.Collect - to reduce the chances of a GC.
    It's not reliable but it seems that the compacting GC doesn't always move the array since the code works sometimes, but only partially - but even then VS doesn't like the array, saying that it is not availabe or has been optimized away (which it isn't because of the ToString() call at the end).
    Friday, September 12, 2008 12:37 PM