Initialization of memory allocated with stackalloc
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty{ height:90px;width:728px;box-sizing:border-box;
}
If I'm allocating memory with stackalloc in C#, is that memory initialized (with 0)?
The documentation doesn't speak of that and only tells that the correct amount is reserved.
In my tests such memory defaulted to 0, but that doesn't mean it's guaranteed though.
c# unsafe stackalloc
add a comment |
If I'm allocating memory with stackalloc in C#, is that memory initialized (with 0)?
The documentation doesn't speak of that and only tells that the correct amount is reserved.
In my tests such memory defaulted to 0, but that doesn't mean it's guaranteed though.
c# unsafe stackalloc
add a comment |
If I'm allocating memory with stackalloc in C#, is that memory initialized (with 0)?
The documentation doesn't speak of that and only tells that the correct amount is reserved.
In my tests such memory defaulted to 0, but that doesn't mean it's guaranteed though.
c# unsafe stackalloc
If I'm allocating memory with stackalloc in C#, is that memory initialized (with 0)?
The documentation doesn't speak of that and only tells that the correct amount is reserved.
In my tests such memory defaulted to 0, but that doesn't mean it's guaranteed though.
c# unsafe stackalloc
c# unsafe stackalloc
asked Dec 30 '11 at 11:37
frumbaelafrumbaela
1866
1866
add a comment |
add a comment |
2 Answers
2
active
oldest
votes
From the spec:
18.8 Stack allocation
The content of the newly allocated memory is undefined.
Now that the stackalloc can be used in "safe" context with Span<T>, does this still hold true?
– JBeurer
Jan 1 at 21:39
add a comment |
Yes, the spec says it is undefined, but the compiler emits localloc CIL intruction for stackalloc. And this is what ECMA Specs says about localloc:
The localloc instruction allocates size (type native unsigned int)
bytes from the local dynamic memory pool and returns the address (a
managed pointer, type &) of the first allocated byte. The block of
memory returned is initialized to 0 only if the initialize flag on the
method is true (see Partition I). The area of memory is newly
allocated. When the current method returns the local memory pool is
available for reuse.
The initialize flag, also known as localsinit flag, is emitted for every method by the compiler because it is required for verifiable code.
Please look at this issue on coreclr asking to stop zeroing memory on stackalloc. At the end of the issue jkotas says:
The current plan is:
C# will keep zero initializing by default. Changing the default would
be too breaking. We have a set of issues opened to make the zero
initialization done by the JIT more efficient or reduce need for it
(#13827, #13823, #13825) Folks who really want to get the last bit of
performance by avoiding zero initialization can use custom ILLinker
step (mono/linker#159) when they know what they are doing. We do this
for CoreLib today (via VM hack, but we should switch to the ILLinker),
and we plan to experiment with this in CoreFX (dotnet/corefx#25956).
Based on the results of these experiments, we may consider introducing
a more streamlined way to do this in future. @ahsonkhan You should
consider experimenting with it in CoreFXLab as well if you believe
that it would help.
And see this csharplang proposal
So the conclusion is: the memory is initialized to zero in practice
However there is a bug/feature in the compiler that prevents from emiting localsinit flag. Unsafe methods that don't declare other variables and use the stack allocated variable only to passing it to other method, don't get marked with the localsinit flag.
Here is an example of such bug/feature:
using System;
using System.Diagnostics;
using System.Runtime.CompilerServices;
namespace InformalTests
{
class Program
{
const int n = 100_000_000;
static unsafe void Main(string args)
{
var watch = Stopwatch.StartNew();
for (int i =0; i < n; i++)
{
ThisMethodDoes_NOT_InitializeStackAllocatedMemory();
}
watch.Stop();
Console.WriteLine($"NOT INITIALIZED elapsed time {watch.Elapsed}");
watch.Restart();
for (int i = 0; i < n; i++)
{
ThisMethodInitializeStackAllocatedMemory();
}
watch.Stop();
Console.WriteLine($"INITIALIZED Elapsed time {watch.Elapsed}");
}
private static unsafe string ThisMethodDoes_NOT_InitializeStackAllocatedMemory()
{
// avoid declaring other local vars, or doing work with stackalloc
// to prevent the .locals init cil flag , see: https://github.com/dotnet/coreclr/issues/1279
char* pointer = stackalloc char[256];
return CreateString(pointer, 256);
}
private static unsafe string ThisMethodInitializeStackAllocatedMemory()
{
//Declaring a variable other than the stackallocated, causes
//compiler to emit .locals int cil flag, so it's slower
int i = 256;
char* pointer = stackalloc char[256];
return CreateString(pointer, i);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static unsafe string CreateString(char* pointer, int length)
{
return "";
}
}
}
The not initialized method is five times faster than the initialized one.
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f8679052%2finitialization-of-memory-allocated-with-stackalloc%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
From the spec:
18.8 Stack allocation
The content of the newly allocated memory is undefined.
Now that the stackalloc can be used in "safe" context with Span<T>, does this still hold true?
– JBeurer
Jan 1 at 21:39
add a comment |
From the spec:
18.8 Stack allocation
The content of the newly allocated memory is undefined.
Now that the stackalloc can be used in "safe" context with Span<T>, does this still hold true?
– JBeurer
Jan 1 at 21:39
add a comment |
From the spec:
18.8 Stack allocation
The content of the newly allocated memory is undefined.
From the spec:
18.8 Stack allocation
The content of the newly allocated memory is undefined.
answered Dec 30 '11 at 11:44
user703016user703016
31.4k676102
31.4k676102
Now that the stackalloc can be used in "safe" context with Span<T>, does this still hold true?
– JBeurer
Jan 1 at 21:39
add a comment |
Now that the stackalloc can be used in "safe" context with Span<T>, does this still hold true?
– JBeurer
Jan 1 at 21:39
Now that the stackalloc can be used in "safe" context with Span<T>, does this still hold true?
– JBeurer
Jan 1 at 21:39
Now that the stackalloc can be used in "safe" context with Span<T>, does this still hold true?
– JBeurer
Jan 1 at 21:39
add a comment |
Yes, the spec says it is undefined, but the compiler emits localloc CIL intruction for stackalloc. And this is what ECMA Specs says about localloc:
The localloc instruction allocates size (type native unsigned int)
bytes from the local dynamic memory pool and returns the address (a
managed pointer, type &) of the first allocated byte. The block of
memory returned is initialized to 0 only if the initialize flag on the
method is true (see Partition I). The area of memory is newly
allocated. When the current method returns the local memory pool is
available for reuse.
The initialize flag, also known as localsinit flag, is emitted for every method by the compiler because it is required for verifiable code.
Please look at this issue on coreclr asking to stop zeroing memory on stackalloc. At the end of the issue jkotas says:
The current plan is:
C# will keep zero initializing by default. Changing the default would
be too breaking. We have a set of issues opened to make the zero
initialization done by the JIT more efficient or reduce need for it
(#13827, #13823, #13825) Folks who really want to get the last bit of
performance by avoiding zero initialization can use custom ILLinker
step (mono/linker#159) when they know what they are doing. We do this
for CoreLib today (via VM hack, but we should switch to the ILLinker),
and we plan to experiment with this in CoreFX (dotnet/corefx#25956).
Based on the results of these experiments, we may consider introducing
a more streamlined way to do this in future. @ahsonkhan You should
consider experimenting with it in CoreFXLab as well if you believe
that it would help.
And see this csharplang proposal
So the conclusion is: the memory is initialized to zero in practice
However there is a bug/feature in the compiler that prevents from emiting localsinit flag. Unsafe methods that don't declare other variables and use the stack allocated variable only to passing it to other method, don't get marked with the localsinit flag.
Here is an example of such bug/feature:
using System;
using System.Diagnostics;
using System.Runtime.CompilerServices;
namespace InformalTests
{
class Program
{
const int n = 100_000_000;
static unsafe void Main(string args)
{
var watch = Stopwatch.StartNew();
for (int i =0; i < n; i++)
{
ThisMethodDoes_NOT_InitializeStackAllocatedMemory();
}
watch.Stop();
Console.WriteLine($"NOT INITIALIZED elapsed time {watch.Elapsed}");
watch.Restart();
for (int i = 0; i < n; i++)
{
ThisMethodInitializeStackAllocatedMemory();
}
watch.Stop();
Console.WriteLine($"INITIALIZED Elapsed time {watch.Elapsed}");
}
private static unsafe string ThisMethodDoes_NOT_InitializeStackAllocatedMemory()
{
// avoid declaring other local vars, or doing work with stackalloc
// to prevent the .locals init cil flag , see: https://github.com/dotnet/coreclr/issues/1279
char* pointer = stackalloc char[256];
return CreateString(pointer, 256);
}
private static unsafe string ThisMethodInitializeStackAllocatedMemory()
{
//Declaring a variable other than the stackallocated, causes
//compiler to emit .locals int cil flag, so it's slower
int i = 256;
char* pointer = stackalloc char[256];
return CreateString(pointer, i);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static unsafe string CreateString(char* pointer, int length)
{
return "";
}
}
}
The not initialized method is five times faster than the initialized one.
add a comment |
Yes, the spec says it is undefined, but the compiler emits localloc CIL intruction for stackalloc. And this is what ECMA Specs says about localloc:
The localloc instruction allocates size (type native unsigned int)
bytes from the local dynamic memory pool and returns the address (a
managed pointer, type &) of the first allocated byte. The block of
memory returned is initialized to 0 only if the initialize flag on the
method is true (see Partition I). The area of memory is newly
allocated. When the current method returns the local memory pool is
available for reuse.
The initialize flag, also known as localsinit flag, is emitted for every method by the compiler because it is required for verifiable code.
Please look at this issue on coreclr asking to stop zeroing memory on stackalloc. At the end of the issue jkotas says:
The current plan is:
C# will keep zero initializing by default. Changing the default would
be too breaking. We have a set of issues opened to make the zero
initialization done by the JIT more efficient or reduce need for it
(#13827, #13823, #13825) Folks who really want to get the last bit of
performance by avoiding zero initialization can use custom ILLinker
step (mono/linker#159) when they know what they are doing. We do this
for CoreLib today (via VM hack, but we should switch to the ILLinker),
and we plan to experiment with this in CoreFX (dotnet/corefx#25956).
Based on the results of these experiments, we may consider introducing
a more streamlined way to do this in future. @ahsonkhan You should
consider experimenting with it in CoreFXLab as well if you believe
that it would help.
And see this csharplang proposal
So the conclusion is: the memory is initialized to zero in practice
However there is a bug/feature in the compiler that prevents from emiting localsinit flag. Unsafe methods that don't declare other variables and use the stack allocated variable only to passing it to other method, don't get marked with the localsinit flag.
Here is an example of such bug/feature:
using System;
using System.Diagnostics;
using System.Runtime.CompilerServices;
namespace InformalTests
{
class Program
{
const int n = 100_000_000;
static unsafe void Main(string args)
{
var watch = Stopwatch.StartNew();
for (int i =0; i < n; i++)
{
ThisMethodDoes_NOT_InitializeStackAllocatedMemory();
}
watch.Stop();
Console.WriteLine($"NOT INITIALIZED elapsed time {watch.Elapsed}");
watch.Restart();
for (int i = 0; i < n; i++)
{
ThisMethodInitializeStackAllocatedMemory();
}
watch.Stop();
Console.WriteLine($"INITIALIZED Elapsed time {watch.Elapsed}");
}
private static unsafe string ThisMethodDoes_NOT_InitializeStackAllocatedMemory()
{
// avoid declaring other local vars, or doing work with stackalloc
// to prevent the .locals init cil flag , see: https://github.com/dotnet/coreclr/issues/1279
char* pointer = stackalloc char[256];
return CreateString(pointer, 256);
}
private static unsafe string ThisMethodInitializeStackAllocatedMemory()
{
//Declaring a variable other than the stackallocated, causes
//compiler to emit .locals int cil flag, so it's slower
int i = 256;
char* pointer = stackalloc char[256];
return CreateString(pointer, i);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static unsafe string CreateString(char* pointer, int length)
{
return "";
}
}
}
The not initialized method is five times faster than the initialized one.
add a comment |
Yes, the spec says it is undefined, but the compiler emits localloc CIL intruction for stackalloc. And this is what ECMA Specs says about localloc:
The localloc instruction allocates size (type native unsigned int)
bytes from the local dynamic memory pool and returns the address (a
managed pointer, type &) of the first allocated byte. The block of
memory returned is initialized to 0 only if the initialize flag on the
method is true (see Partition I). The area of memory is newly
allocated. When the current method returns the local memory pool is
available for reuse.
The initialize flag, also known as localsinit flag, is emitted for every method by the compiler because it is required for verifiable code.
Please look at this issue on coreclr asking to stop zeroing memory on stackalloc. At the end of the issue jkotas says:
The current plan is:
C# will keep zero initializing by default. Changing the default would
be too breaking. We have a set of issues opened to make the zero
initialization done by the JIT more efficient or reduce need for it
(#13827, #13823, #13825) Folks who really want to get the last bit of
performance by avoiding zero initialization can use custom ILLinker
step (mono/linker#159) when they know what they are doing. We do this
for CoreLib today (via VM hack, but we should switch to the ILLinker),
and we plan to experiment with this in CoreFX (dotnet/corefx#25956).
Based on the results of these experiments, we may consider introducing
a more streamlined way to do this in future. @ahsonkhan You should
consider experimenting with it in CoreFXLab as well if you believe
that it would help.
And see this csharplang proposal
So the conclusion is: the memory is initialized to zero in practice
However there is a bug/feature in the compiler that prevents from emiting localsinit flag. Unsafe methods that don't declare other variables and use the stack allocated variable only to passing it to other method, don't get marked with the localsinit flag.
Here is an example of such bug/feature:
using System;
using System.Diagnostics;
using System.Runtime.CompilerServices;
namespace InformalTests
{
class Program
{
const int n = 100_000_000;
static unsafe void Main(string args)
{
var watch = Stopwatch.StartNew();
for (int i =0; i < n; i++)
{
ThisMethodDoes_NOT_InitializeStackAllocatedMemory();
}
watch.Stop();
Console.WriteLine($"NOT INITIALIZED elapsed time {watch.Elapsed}");
watch.Restart();
for (int i = 0; i < n; i++)
{
ThisMethodInitializeStackAllocatedMemory();
}
watch.Stop();
Console.WriteLine($"INITIALIZED Elapsed time {watch.Elapsed}");
}
private static unsafe string ThisMethodDoes_NOT_InitializeStackAllocatedMemory()
{
// avoid declaring other local vars, or doing work with stackalloc
// to prevent the .locals init cil flag , see: https://github.com/dotnet/coreclr/issues/1279
char* pointer = stackalloc char[256];
return CreateString(pointer, 256);
}
private static unsafe string ThisMethodInitializeStackAllocatedMemory()
{
//Declaring a variable other than the stackallocated, causes
//compiler to emit .locals int cil flag, so it's slower
int i = 256;
char* pointer = stackalloc char[256];
return CreateString(pointer, i);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static unsafe string CreateString(char* pointer, int length)
{
return "";
}
}
}
The not initialized method is five times faster than the initialized one.
Yes, the spec says it is undefined, but the compiler emits localloc CIL intruction for stackalloc. And this is what ECMA Specs says about localloc:
The localloc instruction allocates size (type native unsigned int)
bytes from the local dynamic memory pool and returns the address (a
managed pointer, type &) of the first allocated byte. The block of
memory returned is initialized to 0 only if the initialize flag on the
method is true (see Partition I). The area of memory is newly
allocated. When the current method returns the local memory pool is
available for reuse.
The initialize flag, also known as localsinit flag, is emitted for every method by the compiler because it is required for verifiable code.
Please look at this issue on coreclr asking to stop zeroing memory on stackalloc. At the end of the issue jkotas says:
The current plan is:
C# will keep zero initializing by default. Changing the default would
be too breaking. We have a set of issues opened to make the zero
initialization done by the JIT more efficient or reduce need for it
(#13827, #13823, #13825) Folks who really want to get the last bit of
performance by avoiding zero initialization can use custom ILLinker
step (mono/linker#159) when they know what they are doing. We do this
for CoreLib today (via VM hack, but we should switch to the ILLinker),
and we plan to experiment with this in CoreFX (dotnet/corefx#25956).
Based on the results of these experiments, we may consider introducing
a more streamlined way to do this in future. @ahsonkhan You should
consider experimenting with it in CoreFXLab as well if you believe
that it would help.
And see this csharplang proposal
So the conclusion is: the memory is initialized to zero in practice
However there is a bug/feature in the compiler that prevents from emiting localsinit flag. Unsafe methods that don't declare other variables and use the stack allocated variable only to passing it to other method, don't get marked with the localsinit flag.
Here is an example of such bug/feature:
using System;
using System.Diagnostics;
using System.Runtime.CompilerServices;
namespace InformalTests
{
class Program
{
const int n = 100_000_000;
static unsafe void Main(string args)
{
var watch = Stopwatch.StartNew();
for (int i =0; i < n; i++)
{
ThisMethodDoes_NOT_InitializeStackAllocatedMemory();
}
watch.Stop();
Console.WriteLine($"NOT INITIALIZED elapsed time {watch.Elapsed}");
watch.Restart();
for (int i = 0; i < n; i++)
{
ThisMethodInitializeStackAllocatedMemory();
}
watch.Stop();
Console.WriteLine($"INITIALIZED Elapsed time {watch.Elapsed}");
}
private static unsafe string ThisMethodDoes_NOT_InitializeStackAllocatedMemory()
{
// avoid declaring other local vars, or doing work with stackalloc
// to prevent the .locals init cil flag , see: https://github.com/dotnet/coreclr/issues/1279
char* pointer = stackalloc char[256];
return CreateString(pointer, 256);
}
private static unsafe string ThisMethodInitializeStackAllocatedMemory()
{
//Declaring a variable other than the stackallocated, causes
//compiler to emit .locals int cil flag, so it's slower
int i = 256;
char* pointer = stackalloc char[256];
return CreateString(pointer, i);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static unsafe string CreateString(char* pointer, int length)
{
return "";
}
}
}
The not initialized method is five times faster than the initialized one.
edited Nov 25 '18 at 10:03
answered Nov 6 '18 at 14:30
Jesús LópezJesús López
4,28411542
4,28411542
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f8679052%2finitialization-of-memory-allocated-with-stackalloc%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown