-
Notifications
You must be signed in to change notification settings - Fork 4.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Provide Marshal.Alloc api that accepts alignment argument #33244
Comments
This needs to be a new pair of alloc / free APIs to make it cross-platform. There is no away to allocate aligned HGlobal memory on Windows. These APIs need to map to |
The downside of pinnable heap is that it does not provide explicit lifetime control, so it is not suitable for large buffers where you cannot depend on GC for lifetime control. If we were to implement this API, I think we would make it a thin wrapper over
|
I've removed |
+1 for this, would come in handy when working with FILE_FLAG_NO_BUFFERING. |
+1 from me as well, an overload of |
@adamsitnik We need to get the API shape finalized first - see #33244 (comment). The implementation itself is trivial. I have shared the portable version in #33244 (comment) . Optionally, we can also have a more optimized implementation for platforms where |
I'd really rather we didn't implement this API in terms of
|
I won't disagree that a fast explicit lifetime allocator would be nice. It is what the POH and ArrayPool should really be. |
POH was designed to solve a specific category of problems and being "a fast explicit lifetime allocator" was never one of its goals. a good way for us to move forward is to illustrate the current problems with ArrayPool and what behavior you want it to have with usage examples. then we can talk about whether a GC mechanism is needed. I will open an issue for us to discuss that. |
I opened #52098 to track this discussion |
@jkotas I've updated the proposal and marked it as ready for review. PTAL When it comes to implementaiton it has to be simply as fast as possible because it would be used mostly for high perf scenarios. |
I have edited the proposal above some more:
Some questions up for discussion:
|
I'd like us to:
Would it be worth just having these on Note on the below: I'm definitely not saying we need or should expose all of these, this is just giving an example that this is quite a "varied" space and there is room to do quite a bit here just from what POSIX/Windows expose. For example, the set of "standard" APIs that
It also provides some "extended" APIs:
It also provides some It also provides some POSIX/Windows functions, such as:
|
Agree with Tanner's comments about preferring to take nuint instead of nint. We're not explicitly stating that these are equivalent to calling |
Why not? I have explicitly stated it in the comments in my edit of the proposal. I do not see enough value in .NET ever providing private implementation of malloc/free in the core platform. |
I'd agree here. I think documenting ourselves as calling I think its only problematic for us to tie ourselves to actual platform APIs, like |
I don't care if we wrap |
We can document that this does not work with statically linker CRT or legacy SxS CRTs on Windows. Otherwise, I think it would be fine to document that this wraps C malloc/free. There is one-and-only CRT per process in any recent OS. It is not unusual for library APIs to depend on it, in particular on Unix. |
namespace System.Runtime.InteropServices
{
public static class NativeMemory
{
public static unsafe void* Calloc(nuint elementCount, nuint elementSize);
public static unsafe void* Malloc(nuint byteCount);
public static unsafe void* Realloc(void* ptr, nuint byteCount);
public static unsafe void Free(void* ptr);
public static unsafe void* AlignedAlloc(nuint alignment, nuint byteCount);
// This may not be needed, if all of our runtimes guarantee that AlignedAlloc can be passed straight to Free.
public static unsafe void AlignedFree(void* ptr);
}
} |
Are the APIs going to throw OOM or return NULL on failure? It would make sense for them to throw - everybody would have to check for null otherwise, but then it is confusing that they use the C names since the C functions are non-throwing.
The reason for why not - Calloc tends to be a pit of failure from performance point of view since it has to return zero-filled memory. |
Agree. They should throw rather than return nullptr.
I don't think this will be an issue. The names indicate "this is a thin wrapper around the CRT functions." Adding minimal .NET-specific policy (like throwing instead of returning nullptr) shouldn't be a dealbreaker even if we keep these names.
Wouldn't perf-oriented people naturally tend to shy away from calloc? The scenarios where I've used it are scenarios where I needed the zero-init guarantees. |
If it has mimimal .NET-specific policy, it should also have mimimal .NET-specific name. I would call it
You need to read fine print in the manual to understand the differences. Many people see |
I've always known it as "clear-alloc", so the multiplying thing confuses me, since it hides my intent of cleared memory. (So I just pass 1 for elsize) |
I'm fine with this suggestion. We gave the hardware intrinsics .NET-friendly names, after all. If we rename 'Malloc', we should also rename 'Calloc'. I'm otherwise fine with 'AlignedAlloc' and 'Free'. |
Other popular Do we really need |
Not strictly speaking, but it rounds out the exposed APIs to match those in C11 and C++17. |
As per #54006 the API surface has changed somewhat and was approved via an internal e-mail to @dotnet/fxdc namespace System.Runtime.InteropServices
{
public static class NativeMemory
{
public static unsafe void* Alloc(nuint byteCount);
public static unsafe void* Alloc(nuint elementCount, nuint elementSize);
public static unsafe void* AllocZeroed(nuint byteCount);
public static unsafe void* AllocZeroed(nuint elementCount, nuint elementSize);
public static unsafe void* Realloc(void* ptr, nuint byteCount);
public static unsafe void Free(void* ptr);
public static unsafe void* AlignedAlloc(nuint byteCount, nuint alignment);
public static unsafe void AlignedFree(void* ptr);
public static unsafe void* AlignedRealloc(void* ptr, nuint byteCount, nuint alignment);
}
} In particular:
|
API proposal
Rationale
The alignment returned by
Marshal.AllocHGlobal
may differ based on machine architecture and OS, see #33228. Some native APIs require specific memory alignment, some operations offer much better performance when the memory is aligned.Example
Implementation
On posix platform, this may be implemented using posix_memalign.
The text was updated successfully, but these errors were encountered: