The stackalloc keyword is used to allocate a block of memory directly on the stack. This can produce significant performance gains. There is one major caveat: .NET threads have a default stack size of 1MB. Using an stackalloc array with a large number of elements can easily cause a StackOverflowException.
To realize stackalloc's potential with large arrays, we can initialize a separate worker thread with a stack size. The new stack size should be a sum of the expected total maximum data size and the default stack size of 1MB in bytes.
private static void ModifiedStack() { //10 million elements: const int DATA_SIZE = 10000000; //Calculate data size: const int EXPECTED_MAXIMUM_DATA_SIZE = sizeof(int) * DATA_SIZE; //New Thread receives a stack size of 1MB + expected maximum data size. const int NEW_THREAD_STACK_SIZE = 1048576 + EXPECTED_MAXIMUM_DATA_SIZE; //Initialize the Thread with maxStackSize = NEW_THREAD_STACK_SIZE System.Threading.Thread worker = new System.Threading.Thread(() => { unsafe { int* c = stackalloc int[DATA_SIZE]; } }, maxStackSize: NEW_THREAD_STACK_SIZE); //Start the Thread and block the calling Thread worker.Start(); worker.Join(); }
Alternatively, I have created an extension method in a static class to improve usability:
/// <summary> /// Joins the Thread with an Action run on a new Thread. /// Blocks the calling thread until the Action completes. /// </summary> /// <param name="thread">The Thread to block.</param> /// <param name="del">A method to call on the new Thread.</param> /// <param name="expectedDataSize">The total expected size of data /// that will be placed on the stack.</param> public static void Join(this System.Threading.Thread thread, System.Action del, int expectedDataSize) { if (expectedDataSize < 0) throw new ArgumentException("expectedDataSize must be greater than or equal to 0.", "expectedDataSize"); //Initialize the Thread with maxStackSize = 1MB + expectedDataSize System.Threading.Thread worker = new System.Threading.Thread(() => del(), maxStackSize: 1048576 + expectedDataSize); //Start the Thread and block the calling Thread worker.Start(); worker.Join(); }
The extension method can be used by calling the Join method of a Thread with a method and expected maximum data size.
private static void ExtensionMethodModifiedStack() { //Create 10 Million Elements: const int DATA_SIZE = 10000000; //Calculate data size: const int EXPECTED_MAXIMUM_DATA_SIZE = sizeof(int) * DATA_SIZE; System.Threading.Thread.CurrentThread.Join(() => { unsafe { int* c = stackalloc int[DATA_SIZE]; } }, expectedDataSize: EXPECTED_MAXIMUM_DATA_SIZE); }