Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <h1>Purely C# Approach</h1> <p>So, there are a few options. The easiest is to use new/delete in an unsafe context for structs. The second is to use built-in Marshalling services to deal with unmanaged memory (code for this is visible below). However, both of these deal with structs (though I think the latter method is very close to what you want). My code has a limitation in that you must stick to structures throughout and use IntPtrs for references (using ChunkAllocator.ConvertPointerToStructure to get the data and ChunkAllocator.StoreStructure to store the changed data). This is obviously cumbersome, so you'd better <em>really</em> want the performance if you use my approach. However, if you are dealing with <em>only</em> value-types, this approach is sufficient.</p> <h1>Detour: Classes in the CLR</h1> <p>Classes have a 8 byte "prefix" in their allocated memory. Four bytes are for the sync index for multithreading, and four bytes are for identifying their type (basically, virtual method table and run-time reflection). This makes it hard to deal with unamanaged memory since these are CLR specific and since the sync index can change during run-time. See <a href="http://msdn.microsoft.com/en-us/magazine/cc163791.aspx" rel="nofollow">here</a> for details on run-time object creation and <a href="http://www.codeproject.com/Articles/20481/NET-Type-Internals-From-a-Microsoft-CLR-Perspecti#4" rel="nofollow">here</a> for an overview of memory layout for a reference type. Also check out <a href="http://rads.stackoverflow.com/amzn/click/0735627045" rel="nofollow">CLR via C#</a> for a more in-depth explanation.</p> <h3>A Caveat</h3> <p>As usual, things are rarely so simple as yes/no. The real complexity of reference types has to do with how the garbage collector compacts allocated memory during a garbage collection. If you can somehow ensure that a garbage collection doesn't happen or that it won't affect the data in question (see the <a href="http://msdn.microsoft.com/en-US/library/f58wzh21%28v=VS.80%29.aspx" rel="nofollow">fixed keyword</a>) then you can turn an arbitrary pointer into an object reference (just offset the pointer by 8 bytes, then interpret that data as a struct with the same fields and memory layout; perhaps use <a href="http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.structlayoutattribute.aspx" rel="nofollow">StructLayoutAttribute</a> to be sure). I would experiment with non-virtual methods to see if they work; they should (especially if you put them on the struct) but virtual methods are no-go due to the virtual method table that you'd have to discard.</p> <h1>One Does Not Simply Walk Into Mordor</h1> <p>Simply put, this means that managed reference types (classes) cannot be allocated in unmanaged memory. You could use managed reference types in C++, but those would be subject to garbage collection... and the process and code is more painful than the <code>struct</code>-based approach. Where does that leave us? Back where we started, of course.</p> <h1>There is a Secret Way</h1> <p>We could brave <strike>Shelob's Lair</strike> memory allocation ourselves. Unfortunately, this is where our paths must part, because I am not that knowledgeable about it. I will provide you with a <a href="http://flylib.com/books/en/4.331.1.19/1/" rel="nofollow">link</a> or <a href="http://flylib.com/books/en/4.331.1.20/1/" rel="nofollow">two</a> - perhaps <a href="http://msdn.microsoft.com/en-us/library/ms164513%28v=vs.85%29" rel="nofollow">three</a> or <a href="http://community.bartdesmet.net/blogs/bart/archive/2005/07/24/2984.aspx" rel="nofollow">four</a> in actuality. This is rather complicated and begs the question: Are there other optimizations you could try? Cache coherency and superior algorithms is one approach, as is judicious application of P/Invoke for performance-critical code. You could also apply the aforementioned structures-only memory allocation for key methods/classes.</p> <p>Good luck, and let us know if you find a superior alternative.</p> <h1>Appendix: Source Code</h1> <h2>ChunkAllocator.cs</h2> <pre><code>using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Runtime.InteropServices; namespace MemAllocLib { public sealed class ChunkAllocator : IDisposable { IntPtr m_chunkStart; int m_offset;//offset from already allocated memory readonly int m_size; public ChunkAllocator(int memorySize = 1024) { if (memorySize &lt; 1) throw new ArgumentOutOfRangeException("memorySize must be positive"); m_size = memorySize; m_chunkStart = Marshal.AllocHGlobal(memorySize); } ~ChunkAllocator() { Dispose(); } public IntPtr Allocate&lt;T&gt;() where T : struct { int reqBytes = Marshal.SizeOf(typeof(T));//not highly performant return Allocate&lt;T&gt;(reqBytes); } public IntPtr Allocate&lt;T&gt;(int reqBytes) where T : struct { if (m_chunkStart == IntPtr.Zero) throw new ObjectDisposedException("ChunkAllocator"); if (m_offset + reqBytes &gt; m_size) throw new OutOfMemoryException("Too many bytes allocated: " + reqBytes + " needed, but only " + (m_size - m_offset) + " bytes available"); T created = default(T); Marshal.StructureToPtr(created, m_chunkStart + m_offset, false); m_offset += reqBytes; return m_chunkStart + (m_offset - reqBytes); } public void Dispose() { if (m_chunkStart != IntPtr.Zero) { Marshal.FreeHGlobal(m_chunkStart); m_offset = 0; m_chunkStart = IntPtr.Zero; } } public void ReleaseAllMemory() { m_offset = 0; } public int AllocatedMemory { get { return m_offset; } } public int AvailableMemory { get { return m_size - m_offset; } } public int TotalMemory { get { return m_size; } } public static T ConvertPointerToStruct&lt;T&gt;(IntPtr ptr) where T : struct { return (T)Marshal.PtrToStructure(ptr, typeof(T)); } public static void StoreStructure&lt;T&gt;(IntPtr ptr, T data) where T : struct { Marshal.StructureToPtr(data, ptr, false); } } } </code></pre> <h2>Program.cs</h2> <pre><code>using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace MemoryAllocation { class Program { static void Main(string[] args) { using (MemAllocLib.ChunkAllocator chunk = new MemAllocLib.ChunkAllocator()) { Console.WriteLine("&gt;&gt; Simple data test"); SimpleDataTest(chunk); Console.WriteLine(); Console.WriteLine("&gt;&gt; Complex data test"); ComplexDataTest(chunk); } Console.ReadLine(); } private static void SimpleDataTest(MemAllocLib.ChunkAllocator chunk) { IntPtr ptr = chunk.Allocate&lt;System.Int32&gt;(); Console.WriteLine(MemAllocLib.ChunkAllocator.ConvertPointerToStruct&lt;Int32&gt;(ptr)); System.Diagnostics.Debug.Assert(MemAllocLib.ChunkAllocator.ConvertPointerToStruct&lt;Int32&gt;(ptr) == 0, "Data not initialized properly"); System.Diagnostics.Debug.Assert(chunk.AllocatedMemory == sizeof(Int32), "Data not allocated properly"); int data = MemAllocLib.ChunkAllocator.ConvertPointerToStruct&lt;Int32&gt;(ptr); data = 10; MemAllocLib.ChunkAllocator.StoreStructure(ptr, data); Console.WriteLine(MemAllocLib.ChunkAllocator.ConvertPointerToStruct&lt;Int32&gt;(ptr)); System.Diagnostics.Debug.Assert(MemAllocLib.ChunkAllocator.ConvertPointerToStruct&lt;Int32&gt;(ptr) == 10, "Data not set properly"); Console.WriteLine("All tests passed"); } private static void ComplexDataTest(MemAllocLib.ChunkAllocator chunk) { IntPtr ptr = chunk.Allocate&lt;Person&gt;(); Console.WriteLine(MemAllocLib.ChunkAllocator.ConvertPointerToStruct&lt;Person&gt;(ptr)); System.Diagnostics.Debug.Assert(MemAllocLib.ChunkAllocator.ConvertPointerToStruct&lt;Person&gt;(ptr).Age == 0, "Data age not initialized properly"); System.Diagnostics.Debug.Assert(MemAllocLib.ChunkAllocator.ConvertPointerToStruct&lt;Person&gt;(ptr).Name == null, "Data name not initialized properly"); System.Diagnostics.Debug.Assert(chunk.AllocatedMemory == System.Runtime.InteropServices.Marshal.SizeOf(typeof(Person)) + sizeof(Int32), "Data not allocated properly"); Person data = MemAllocLib.ChunkAllocator.ConvertPointerToStruct&lt;Person&gt;(ptr); data.Name = "Bob"; data.Age = 20; MemAllocLib.ChunkAllocator.StoreStructure(ptr, data); Console.WriteLine(MemAllocLib.ChunkAllocator.ConvertPointerToStruct&lt;Person&gt;(ptr)); System.Diagnostics.Debug.Assert(MemAllocLib.ChunkAllocator.ConvertPointerToStruct&lt;Person&gt;(ptr).Age == 20, "Data age not set properly"); System.Diagnostics.Debug.Assert(MemAllocLib.ChunkAllocator.ConvertPointerToStruct&lt;Person&gt;(ptr).Name == "Bob", "Data name not set properly"); Console.WriteLine("All tests passed"); } struct Person { public string Name; public int Age; public Person(string name, int age) { Name = name; Age = age; } public override string ToString() { if (string.IsNullOrWhiteSpace(Name)) return "Age is " + Age; return Name + " is " + Age + " years old"; } } } } </code></pre>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload