How to convert ReadOnlyMemory<char> to ReadOnlyMemory<byte> [duplicate] - c#

We can cast Span<T> and ReadOnlySpan<T> to another using MemoryMarshal.Cast method overloads. Like :
Span<byte> span = stackalloc byte[4];
var singleIntSpan = MemoryMarshal.Cast<byte, int>(span);
But is there any way to cast Memory<T> to another? for example cast Memory<byte> to Memory<ushort>.

You can't do it directly; however, if you really need, you can create a custom MemoryManager<T> (presumably actually a MyMemoryManager<TFrom, TTo> : MemoryManager<TTo> that performs the cast as part of the GetSpan() override. This is slightly non-trivial, and demands another allocation - unlike a Span<T> cast, which is allocation-free.
If you need a concrete example of that, I can whip one up (I actually do exactly this in some existing code), but: to be honest, you probably want to reconsider the scenario instead.
Edit: something like this:
using System;
using System.Buffers;
using System.Runtime.InteropServices;
class Program
{
static void Main()
{
Memory<byte> bytes = new byte[1024];
Memory<ushort> typed = Utils.Cast<byte, ushort>(bytes);
Console.WriteLine(typed.Length); // 512
// note CPU endianness matters re the layout
typed.Span[0] = 0x5432;
Console.WriteLine(bytes.Span[0]); // 50 = 0x32
Console.WriteLine(bytes.Span[1]); // 84 = 0x54
}
}
static class Utils
{
public static Memory<TTo> Cast<TFrom, TTo>(Memory<TFrom> from)
where TFrom : unmanaged
where TTo : unmanaged
{
// avoid the extra allocation/indirection, at the cost of a gen-0 box
if (typeof(TFrom) == typeof(TTo)) return (Memory<TTo>)(object)from;
return new CastMemoryManager<TFrom, TTo>(from).Memory;
}
private sealed class CastMemoryManager<TFrom, TTo> : MemoryManager<TTo>
where TFrom : unmanaged
where TTo : unmanaged
{
private readonly Memory<TFrom> _from;
public CastMemoryManager(Memory<TFrom> from) => _from = from;
public override Span<TTo> GetSpan()
=> MemoryMarshal.Cast<TFrom, TTo>(_from.Span);
protected override void Dispose(bool disposing) { }
public override MemoryHandle Pin(int elementIndex = 0)
=> throw new NotSupportedException();
public override void Unpin()
=> throw new NotSupportedException();
}
}
If you really want to support pin/unpin, that should be possible - you'll just need to compute the relative ranges and offsets from the competing TFrom/TTo, though - presumably using Unsafe.SizeOf<T> etc, and using MemoryMarshal.TryGetMemoryManager to get the underlying memory manager (if one - note that naked arrays don't have a memory manager). Unless you're going to extensively test that option, throwing is probably safer than getting it wrong.

I don't think you can, however I guess you can return a span from it, though i doubt it will help
Memory.Span Property
Returns a span from the current instance.
var array = new int[4];
var mem = array.AsMemory();
var span = MemoryMarshal.Cast<int, byte>(mem.Span);

You can use Unsafe.As to cast Memory<TFrom> to Memory<TTo> but you would need to take care of the correct length of Memory<TTo>:
using System.Runtime.CompilerServices;
// test data
var floatData = new float[5];
var floatMemory = floatData.AsMemory();
floatMemory.Span.Fill(1.99f);
// cast
var resizeFactor = sizeof(double) / sizeof(float);
var doubleMemory = Unsafe
.As<Memory<float>, Memory<double>>(ref floatMemory)
.Slice(0, floatMemory.Length / resizeFactor);
Edit: this works as long as the byte size of TTo is larger or equal to TFrom

Related

How can I cast Memory<T> to another

We can cast Span<T> and ReadOnlySpan<T> to another using MemoryMarshal.Cast method overloads. Like :
Span<byte> span = stackalloc byte[4];
var singleIntSpan = MemoryMarshal.Cast<byte, int>(span);
But is there any way to cast Memory<T> to another? for example cast Memory<byte> to Memory<ushort>.
You can't do it directly; however, if you really need, you can create a custom MemoryManager<T> (presumably actually a MyMemoryManager<TFrom, TTo> : MemoryManager<TTo> that performs the cast as part of the GetSpan() override. This is slightly non-trivial, and demands another allocation - unlike a Span<T> cast, which is allocation-free.
If you need a concrete example of that, I can whip one up (I actually do exactly this in some existing code), but: to be honest, you probably want to reconsider the scenario instead.
Edit: something like this:
using System;
using System.Buffers;
using System.Runtime.InteropServices;
class Program
{
static void Main()
{
Memory<byte> bytes = new byte[1024];
Memory<ushort> typed = Utils.Cast<byte, ushort>(bytes);
Console.WriteLine(typed.Length); // 512
// note CPU endianness matters re the layout
typed.Span[0] = 0x5432;
Console.WriteLine(bytes.Span[0]); // 50 = 0x32
Console.WriteLine(bytes.Span[1]); // 84 = 0x54
}
}
static class Utils
{
public static Memory<TTo> Cast<TFrom, TTo>(Memory<TFrom> from)
where TFrom : unmanaged
where TTo : unmanaged
{
// avoid the extra allocation/indirection, at the cost of a gen-0 box
if (typeof(TFrom) == typeof(TTo)) return (Memory<TTo>)(object)from;
return new CastMemoryManager<TFrom, TTo>(from).Memory;
}
private sealed class CastMemoryManager<TFrom, TTo> : MemoryManager<TTo>
where TFrom : unmanaged
where TTo : unmanaged
{
private readonly Memory<TFrom> _from;
public CastMemoryManager(Memory<TFrom> from) => _from = from;
public override Span<TTo> GetSpan()
=> MemoryMarshal.Cast<TFrom, TTo>(_from.Span);
protected override void Dispose(bool disposing) { }
public override MemoryHandle Pin(int elementIndex = 0)
=> throw new NotSupportedException();
public override void Unpin()
=> throw new NotSupportedException();
}
}
If you really want to support pin/unpin, that should be possible - you'll just need to compute the relative ranges and offsets from the competing TFrom/TTo, though - presumably using Unsafe.SizeOf<T> etc, and using MemoryMarshal.TryGetMemoryManager to get the underlying memory manager (if one - note that naked arrays don't have a memory manager). Unless you're going to extensively test that option, throwing is probably safer than getting it wrong.
I don't think you can, however I guess you can return a span from it, though i doubt it will help
Memory.Span Property
Returns a span from the current instance.
var array = new int[4];
var mem = array.AsMemory();
var span = MemoryMarshal.Cast<int, byte>(mem.Span);
You can use Unsafe.As to cast Memory<TFrom> to Memory<TTo> but you would need to take care of the correct length of Memory<TTo>:
using System.Runtime.CompilerServices;
// test data
var floatData = new float[5];
var floatMemory = floatData.AsMemory();
floatMemory.Span.Fill(1.99f);
// cast
var resizeFactor = sizeof(double) / sizeof(float);
var doubleMemory = Unsafe
.As<Memory<float>, Memory<double>>(ref floatMemory)
.Slice(0, floatMemory.Length / resizeFactor);
Edit: this works as long as the byte size of TTo is larger or equal to TFrom

Can I set a fixed length for MemoryStream?

I'm extending BinaryWriter using a MemoryStream.
public class PacketWriter : BinaryWriter
{
public PacketWriter(Opcode op) : base(CreateStream(op))
{
this.Write((ushort)op);
}
private static MemoryStream CreateStream(Opcode op) {
return new MemoryStream(PacketSizes.Get(op));
}
public WriteCustomThing() {
// Validate that MemoryStream has space?
// Do all the stuff
}
}
Ideally, I want to use write using PacketWriter as long as there is space available (which is already defined in PacketSizes). If there isn't space available, I want an exception thrown. It seems like MemoryStream just dynamically allocates more space if you write over capacity, but I want a fixed capacity. Can I achieve this without needing to check the length every time? The only solution I thought of so far was to override all the Write methods of BinaryWriter and compare lengths, but this is annoying.
Just provide a buffer of the desired size to write into:
using System;
using System.IO;
class Test
{
static void Main()
{
var buffer = new byte[3];
var stream = new MemoryStream(buffer);
stream.WriteByte(1);
stream.WriteByte(2);
stream.WriteByte(3);
Console.WriteLine("Three successful writes");
stream.WriteByte(4); // This throws
Console.WriteLine("Four successful writes??");
}
}
This is documented behavior:
Initializes a new non-resizable instance of the MemoryStream class based on the specified byte array.

Understanding of .NET internal StringBuilderCache class configuration

When I was looking at decompiled .NET assemblies to see some internals, I've noticed interesting StringBuilderCache class used by multiple framework's methods:
internal static class StringBuilderCache
{
[ThreadStatic]
private static StringBuilder CachedInstance;
private const int MAX_BUILDER_SIZE = 360;
public static StringBuilder Acquire(int capacity = 16)
{
if (capacity <= 360)
{
StringBuilder cachedInstance = StringBuilderCache.CachedInstance;
if (cachedInstance != null && capacity <= cachedInstance.Capacity)
{
StringBuilderCache.CachedInstance = null;
cachedInstance.Clear();
return cachedInstance;
}
}
return new StringBuilder(capacity);
}
public static void Release(StringBuilder sb)
{
if (sb.Capacity <= 360)
{
StringBuilderCache.CachedInstance = sb;
}
}
public static string GetStringAndRelease(StringBuilder sb)
{
string result = sb.ToString();
StringBuilderCache.Release(sb);
return result;
}
}
Example usage we can find for example in string.Format method:
public static string Format(IFormatProvider provider, string format, params object[] args)
{
...
StringBuilder stringBuilder = StringBuilderCache.Acquire(format.Length + args.Length * 8);
stringBuilder.AppendFormat(provider, format, args);
return StringBuilderCache.GetStringAndRelease(stringBuilder);
}
While it is quite clever and for sure I will remember about such caching pattern, I wonder why MAX_BUILDER_SIZE is so small? Setting it to, let's set 2kB, wouldn't be better? It would prevent from creating bigger StringBuilder instances with a quite little memory overhead.
It is a per-thread cache so a low number is expected. Best to use the Reference Source for questions like this, you'll see the comments as well, which looks like (edited to fit):
// The value 360 was chosen in discussion with performance experts as a
// compromise between using as litle memory (per thread) as possible and
// still covering a large part of short-lived StringBuilder creations on
// the startup path of VS designers.
private const int MAX_BUILDER_SIZE = 360;
"VS designers" is a wee bit puzzling. Well, not really, surely this work was done to optimize Visual Studio. Neelie Kroes would have a field day and the EU would have another billion dollars if she would find out :)
Most strings built are probably small, so using a relatively small buffer size will cover most of the operations while not using up too much memory. Consider that there is a thread pool with possibly many threads being created. If every one of them would take up to 2kB for a cached buffer, it would add up to some amount of memory.

Memory usage serializing chunked byte arrays with Protobuf-net

In our application we have some data structures which amongst other things contain a chunked list of bytes (currently exposed as a List<byte[]>). We chunk bytes up because if we allow the byte arrays to be put on the large object heap then over time we suffer from memory fragmentation.
We've also started using Protobuf-net to serialize these structures, using our own generated serialization DLL.
However we've noticed that Protobuf-net is creating very large in-memory buffers while serializing. Glancing through the source code it appears that perhaps it can't flush its internal buffer until the entire List<byte[]> structure has been written because it needs to write the total length at the front of the buffer afterwards.
This unfortunately undoes our work with chunking the bytes in the first place, and eventually gives us OutOfMemoryExceptions due to memory fragmentation (the exception occurs at the time where Protobuf-net is trying to expand the buffer to over 84k, which obviously puts it on the LOH, and our overall process memory usage is fairly low).
If my analysis of how Protobuf-net is working is correct, is there a way around this issue?
Update
Based on Marc's answer, here is what I've tried:
[ProtoContract]
[ProtoInclude(1, typeof(A), DataFormat = DataFormat.Group)]
public class ABase
{
}
[ProtoContract]
public class A : ABase
{
[ProtoMember(1, DataFormat = DataFormat.Group)]
public B B
{
get;
set;
}
}
[ProtoContract]
public class B
{
[ProtoMember(1, DataFormat = DataFormat.Group)]
public List<byte[]> Data
{
get;
set;
}
}
Then to serialize it:
var a = new A();
var b = new B();
a.B = b;
b.Data = new List<byte[]>
{
Enumerable.Range(0, 1999).Select(v => (byte)v).ToArray(),
Enumerable.Range(2000, 3999).Select(v => (byte)v).ToArray(),
};
var stream = new MemoryStream();
Serializer.Serialize(stream, a);
However if I stick a breakpoint in ProtoWriter.WriteBytes() where it calls DemandSpace() towards the bottom of the method and step into DemandSpace(), I can see that the buffer isn't being flushed because writer.flushLock equals 1.
If I create another base class for ABase like this:
[ProtoContract]
[ProtoInclude(1, typeof(ABase), DataFormat = DataFormat.Group)]
public class ABaseBase
{
}
[ProtoContract]
[ProtoInclude(1, typeof(A), DataFormat = DataFormat.Group)]
public class ABase : ABaseBase
{
}
Then writer.flushLock equals 2 in DemandSpace().
I'm guessing there is an obvious step I've missed here to do with derived types?
I'm going to read between some lines here... because List<T> (mapped as repeated in protobuf parlance) doesn't have an overall length-prefix, and byte[] (mapped as bytes) has a trivial length-prefix that shouldn't cause additional buffering. So I'm guessing what you actually have is more like:
[ProtoContract]
public class A {
[ProtoMember(1)]
public B Foo {get;set;}
}
[ProtoContract]
public class B {
[ProtoMember(1)]
public List<byte[]> Bar {get;set;}
}
Here, the need to buffer for a length-prefix is actually when writing A.Foo, basically to declare "the following complex data is the value for A.Foo"). Fortunately there is a simple fix:
[ProtoMember(1, DataFormat=DataFormat.Group)]
public B Foo {get;set;}
This changes between 2 packing techniques in protobuf:
the default (google's stated preference) is length-prefixed, meaning you get a marker indicating the length of the message to follow, then the sub-message payload
but there is also an option to use a start-marker, the sub-message payload, and an end-marker
When using the second technique it doesn't need to buffer, so: it doesn't. This does mean it will be writing slightly different bytes for the same data, but protobuf-net is very forgiving, and will happily deserialize data from either format here. Meaning: if you make this change, you can still read your existing data, but new data will use the start/end-marker technique.
This demands the question: why do google prefer the length-prefix approach? Probably this is because it is more efficient when reading to skip through fields (either via a raw reader API, or as unwanted/unexpected data) when using the length-prefix approach, as you can just read the length-prefix, and then just progress the stream [n] bytes; by contrast, to skip data with a start/end-marker you still need to crawl through the payload, skipping the sub-fields individually. Of course, this theoretical difference in read performance doesn't apply if you expect that data and want to read it into your object, which you almost certainly do. Also, in the google protobuf implementation, because it isn't working with a regular POCO model, the size of the payloads are already known, so they don't really see the same issue when writing.
Additional re your edit; the [ProtoInclude(..., DataFormat=...)] looks like it simply wasn't being processed. I have added a test for this in my current local build, and it now passes:
[Test]
public void Execute()
{
var a = new A();
var b = new B();
a.B = b;
b.Data = new List<byte[]>
{
Enumerable.Range(0, 1999).Select(v => (byte)v).ToArray(),
Enumerable.Range(2000, 3999).Select(v => (byte)v).ToArray(),
};
var stream = new MemoryStream();
var model = TypeModel.Create();
model.AutoCompile = false;
#if DEBUG // this is only available in debug builds; if set, an exception is
// thrown if the stream tries to buffer
model.ForwardsOnly = true;
#endif
CheckClone(model, a);
model.CompileInPlace();
CheckClone(model, a);
CheckClone(model.Compile(), a);
}
void CheckClone(TypeModel model, A original)
{
int sum = original.B.Data.Sum(x => x.Sum(b => (int)b));
var clone = (A)model.DeepClone(original);
Assert.IsInstanceOfType(typeof(A), clone);
Assert.IsInstanceOfType(typeof(B), clone.B);
Assert.AreEqual(sum, clone.B.Data.Sum(x => x.Sum(b => (int)b)));
}
This commit is tied into some other, unrelated refactorings (some rework for WinRT / IKVM), but should be committed ASAP.

How to instance a C# class in UNmanaged memory? (Possible?)

UPDATE: There is now an accepted answer that "works". You should never, ever, ever, ever use it. Ever.
First let me preface my question by stating that I'm a game developer. There's a legitimate - if highly unusual - performance-related reason for wanting to do this.
Say I have a C# class like this:
class Foo
{
public int a, b, c;
public void MyMethod(int d) { a = d; b = d; c = a + b; }
}
Nothing fancy. Note that it is a reference type that contains only value types.
In managed code I'd like to have something like this:
Foo foo;
foo = Voodoo.NewInUnmanagedMemory<Foo>(); // <- ???
foo.MyMethod(1);
What would the function NewInUnmanagedMemory look like? If it can't be done in C#, could it be done in IL? (Or maybe C++/CLI?)
Basically: Is there a way - no matter how hacky - to turn some totally arbitrary pointer into an object reference. And - short of making the CLR explode - damn the consequences.
(Another way to put my question is: "I want to implement a custom allocator for C#")
This leads to the follow-up question: What does the garbage collector do (implementation-specific, if need be) when faced with a reference that points outside of managed memory?
And, related to that, what would happen if Foo had a reference as a member field? What if it pointed at managed memory? What if it only ever pointed at other objects allocated in unmanaged memory?
Finally, if this is impossible: Why?
Update: Here are the "missing pieces" so far:
#1: How to convert an IntPtr to an object reference? It might be possible though unverifiable IL (see comments). So far I've had no luck with this. The framework seems to be extremely careful to prevent this from happening.
(It would also be nice to be able to get the size and layout information for non-blittable managed types at runtime. Again, the framework tries to make this impossible.)
#2: Assuming problem one can be solved - what does the GC do when it encounters an object reference that points outside of the GC heap? Does it crash? Anton Tykhyy, in his answer, guesses that it will. Given how careful the framework is to prevent #1, it does seem likely. Something that confirms this would be nice.
(Alternatively the object reference could point to pinned memory inside the GC heap. Would that make a difference?)
Based on this, I'm inclined to think that this idea for a hack is impossible - or at least not worth the effort. But I'd be interested to get an answer that goes into the technical details of #1 or #2 or both.
I have been experimenting creating classes in unmanaged memory. It is possible but has a problem I am currently unable to solve - you can't assign objects to reference-type fields -see edit at the bottom-, so you can have only structure fields in your custom class.
This is evil:
using System;
using System.Reflection.Emit;
using System.Runtime.InteropServices;
public class Voodoo<T> where T : class
{
static readonly IntPtr tptr;
static readonly int tsize;
static readonly byte[] zero;
public static T NewInUnmanagedMemory()
{
IntPtr handle = Marshal.AllocHGlobal(tsize);
Marshal.Copy(zero, 0, handle, tsize);
IntPtr ptr = handle+4;
Marshal.WriteIntPtr(ptr, tptr);
return GetO(ptr);
}
public static void FreeUnmanagedInstance(T obj)
{
IntPtr ptr = GetPtr(obj);
IntPtr handle = ptr-4;
Marshal.FreeHGlobal(handle);
}
delegate T GetO_d(IntPtr ptr);
static readonly GetO_d GetO;
delegate IntPtr GetPtr_d(T obj);
static readonly GetPtr_d GetPtr;
static Voodoo()
{
Type t = typeof(T);
tptr = t.TypeHandle.Value;
tsize = Marshal.ReadInt32(tptr, 4);
zero = new byte[tsize];
DynamicMethod m = new DynamicMethod("GetO", typeof(T), new[]{typeof(IntPtr)}, typeof(Voodoo<T>), true);
var il = m.GetILGenerator();
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ret);
GetO = m.CreateDelegate(typeof(GetO_d)) as GetO_d;
m = new DynamicMethod("GetPtr", typeof(IntPtr), new[]{typeof(T)}, typeof(Voodoo<T>), true);
il = m.GetILGenerator();
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ret);
GetPtr = m.CreateDelegate(typeof(GetPtr_d)) as GetPtr_d;
}
}
If you care about memory leak, you should always call FreeUnmanagedInstance when you are done with your class.
If you want more complex solution, you can try this:
using System;
using System.Reflection.Emit;
using System.Runtime.InteropServices;
public class ObjectHandle<T> : IDisposable where T : class
{
bool freed;
readonly IntPtr handle;
readonly T value;
readonly IntPtr tptr;
public ObjectHandle() : this(typeof(T))
{
}
public ObjectHandle(Type t)
{
tptr = t.TypeHandle.Value;
int size = Marshal.ReadInt32(tptr, 4);//base instance size
handle = Marshal.AllocHGlobal(size);
byte[] zero = new byte[size];
Marshal.Copy(zero, 0, handle, size);//zero memory
IntPtr ptr = handle+4;
Marshal.WriteIntPtr(ptr, tptr);//write type ptr
value = GetO(ptr);//convert to reference
}
public T Value{
get{
return value;
}
}
public bool Valid{
get{
return Marshal.ReadIntPtr(handle, 4) == tptr;
}
}
public void Dispose()
{
if(!freed)
{
Marshal.FreeHGlobal(handle);
freed = true;
GC.SuppressFinalize(this);
}
}
~ObjectHandle()
{
Dispose();
}
delegate T GetO_d(IntPtr ptr);
static readonly GetO_d GetO;
static ObjectHandle()
{
DynamicMethod m = new DynamicMethod("GetO", typeof(T), new[]{typeof(IntPtr)}, typeof(ObjectHandle<T>), true);
var il = m.GetILGenerator();
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ret);
GetO = m.CreateDelegate(typeof(GetO_d)) as GetO_d;
}
}
/*Usage*/
using(var handle = new ObjectHandle<MyClass>())
{
//do some work
}
I hope it will help you on your path.
Edit: Found a solution to reference-type fields:
class MyClass
{
private IntPtr a_ptr;
public object a{
get{
return Voodoo<object>.GetO(a_ptr);
}
set{
a_ptr = Voodoo<object>.GetPtr(value);
}
}
public int b;
public int c;
}
Edit: Even better solution. Just use ObjectContainer<object> instead of object and so on.
public struct ObjectContainer<T> where T : class
{
private readonly T val;
public ObjectContainer(T obj)
{
val = obj;
}
public T Value{
get{
return val;
}
}
public static implicit operator T(ObjectContainer<T> #ref)
{
return #ref.val;
}
public static implicit operator ObjectContainer<T>(T obj)
{
return new ObjectContainer<T>(obj);
}
public override string ToString()
{
return val.ToString();
}
public override int GetHashCode()
{
return val.GetHashCode();
}
public override bool Equals(object obj)
{
return val.Equals(obj);
}
}
"I want to implement a custom allocator for C#"
GC is at the core of the CLR. Only Microsoft (or the Mono team in case of Mono) can replace it, at a great cost in development effort. GC being at the core of the CLR, messing around with the GC or the managed heap will crash the CLR — quickly if you're very-very lucky.
What does the garbage collector do (implementation-specific, if need be) when faced with a reference that points outside of managed memory?
It crashes in an implementation-specific way ;)
Purely C# Approach
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 really want the performance if you use my approach. However, if you are dealing with only value-types, this approach is sufficient.
Detour: Classes in the CLR
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 here for details on run-time object creation and here for an overview of memory layout for a reference type. Also check out CLR via C# for a more in-depth explanation.
A Caveat
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 fixed keyword) 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 StructLayoutAttribute 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.
One Does Not Simply Walk Into Mordor
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 struct-based approach. Where does that leave us? Back where we started, of course.
There is a Secret Way
We could brave Shelob's Lair 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 link or two - perhaps three or four 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.
Good luck, and let us know if you find a superior alternative.
Appendix: Source Code
ChunkAllocator.cs
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 < 1)
throw new ArgumentOutOfRangeException("memorySize must be positive");
m_size = memorySize;
m_chunkStart = Marshal.AllocHGlobal(memorySize);
}
~ChunkAllocator()
{
Dispose();
}
public IntPtr Allocate<T>() where T : struct
{
int reqBytes = Marshal.SizeOf(typeof(T));//not highly performant
return Allocate<T>(reqBytes);
}
public IntPtr Allocate<T>(int reqBytes) where T : struct
{
if (m_chunkStart == IntPtr.Zero)
throw new ObjectDisposedException("ChunkAllocator");
if (m_offset + reqBytes > 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<T>(IntPtr ptr) where T : struct
{
return (T)Marshal.PtrToStructure(ptr, typeof(T));
}
public static void StoreStructure<T>(IntPtr ptr, T data) where T : struct
{
Marshal.StructureToPtr(data, ptr, false);
}
}
}
Program.cs
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(">> Simple data test");
SimpleDataTest(chunk);
Console.WriteLine();
Console.WriteLine(">> Complex data test");
ComplexDataTest(chunk);
}
Console.ReadLine();
}
private static void SimpleDataTest(MemAllocLib.ChunkAllocator chunk)
{
IntPtr ptr = chunk.Allocate<System.Int32>();
Console.WriteLine(MemAllocLib.ChunkAllocator.ConvertPointerToStruct<Int32>(ptr));
System.Diagnostics.Debug.Assert(MemAllocLib.ChunkAllocator.ConvertPointerToStruct<Int32>(ptr) == 0, "Data not initialized properly");
System.Diagnostics.Debug.Assert(chunk.AllocatedMemory == sizeof(Int32), "Data not allocated properly");
int data = MemAllocLib.ChunkAllocator.ConvertPointerToStruct<Int32>(ptr);
data = 10;
MemAllocLib.ChunkAllocator.StoreStructure(ptr, data);
Console.WriteLine(MemAllocLib.ChunkAllocator.ConvertPointerToStruct<Int32>(ptr));
System.Diagnostics.Debug.Assert(MemAllocLib.ChunkAllocator.ConvertPointerToStruct<Int32>(ptr) == 10, "Data not set properly");
Console.WriteLine("All tests passed");
}
private static void ComplexDataTest(MemAllocLib.ChunkAllocator chunk)
{
IntPtr ptr = chunk.Allocate<Person>();
Console.WriteLine(MemAllocLib.ChunkAllocator.ConvertPointerToStruct<Person>(ptr));
System.Diagnostics.Debug.Assert(MemAllocLib.ChunkAllocator.ConvertPointerToStruct<Person>(ptr).Age == 0, "Data age not initialized properly");
System.Diagnostics.Debug.Assert(MemAllocLib.ChunkAllocator.ConvertPointerToStruct<Person>(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<Person>(ptr);
data.Name = "Bob";
data.Age = 20;
MemAllocLib.ChunkAllocator.StoreStructure(ptr, data);
Console.WriteLine(MemAllocLib.ChunkAllocator.ConvertPointerToStruct<Person>(ptr));
System.Diagnostics.Debug.Assert(MemAllocLib.ChunkAllocator.ConvertPointerToStruct<Person>(ptr).Age == 20, "Data age not set properly");
System.Diagnostics.Debug.Assert(MemAllocLib.ChunkAllocator.ConvertPointerToStruct<Person>(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";
}
}
}
}
You can write code in C++ and call it from .NET using P/Invoke or you can you can write code in managed C++ that gives you full access to the native API from inside a .NET language. However, on the managed side you can only work with managed types so you will have to encapsulate your unmanaged objects.
To give a simple example: Marshal.AllocHGlobal allows you to allocate memory on the Windows heap. The handle returned is not of much use in .NET but can be required when calling a native Windows API requiring a buffer.
This is not possible.
However you can use a managed struct and create a pointer of this struct type. This pointer can point anywhere (including to unmanaged memory).
The question is, why would you want to have a class in unmanaged memory? You wouldn't get GC features anyway. You can just use a pointer-to-struct.
Nothing like that is possible. You can access managed memory in unsafe context, but said memory is still managed and subject to GC.
Why?
Simplicity and security.
But now that I think about it, I think you can mix managed and unmanaged with C++/CLI. But I'm not sure about that, because I never worked with C++/CLI.
I don't know a way to hold a C# class instance in the unmanaged heap, not even in C++/CLI.
It's possible to design a value-type allocator entirely within .net, without using any unmanaged code, which can allocate and free an arbitrary number of value-type instances without any significant GC pressure. The trick is to create a relatively small number of arrays (possibly one for each type) to hold the instances, and then pass around "instance reference" structs which hold the array indices of the index in question.
Suppose, for example, that I want to have a "creature" class which holds XYZ positions (float), XYZ velocity (also float), roll/pitch/yaw (ditto), damage (float), and kind (enumeration). An interface "ICreatureReference" would define getters and setters for all those properties. A typical implementation would be a struct CreatureReference with a single private field int _index, and property accessors like:
float Position {
get {return Creatures[_index].Position;}
set {Creatures[_index].Position = value;}
};
The system would keep a list of which array slots are used and vacant (it could, if desired, use one of the fields within Creatures to form a linked list of vacant slots). The CreatureReference.Create method would allocate an item from the vacant-items list; the Dispose method of a CreatureReference instance would add its array slot to the vacant-items list.
This approach ends up requiring an annoying amount of boilerplate code, but it can be reasonably efficient and avoid GC pressure. The biggest problems with are probably that (1) it makes structs behave more like reference types than structs, and (2) it requires absolute discipline with calling IDispose, since non-disposed array slots will never get reclaimed. Another irksome quirk is that one will be unable to use property setters for read-only values of type CreatureReference, even though the property setters would not try to mutate any fields of the CreatureReference instance to which they are applied. Using an interface ICreatureReference may avoid this difficulty, but one must be careful to only declare storage locations of generic types constrained to ICreatureReference, rather than declaring storage locations of ICreatureReference.

Categories