C#에서도 자바와 비슷하게 일부 몇 type( struct, value type, reference 변수) 을 제외하면 모두 heap에서 메모리를 할당받는다.
퍼포먼스 측면에서는 heap 보다 stack을 사용하는 것이 훨씬 좋은데,
자바와는 달리 explicit 하게 stack에 메모리를 할당할 수 있다.
(자바는 escape analysis 라는 기법을 통해 implicit 하게 stack allocation을 한다. 즉 프로그래머가 따로 신경쓰지 않아도 된다는 말)
explicit 하게 stack allocation을 사용하려면
1. 포인터를 사용 (문법은 C와 비슷)
2.new 대신 stackalloc 키워드 사용
3.stack allocation 을 하는 메소드 또는 클래스 등(블락 도 되나??? unsafe {} 이렇게) 에 unsafe 키워드 명시
4.컴파일러 옵션에 /unsafe 명시 (VS 2008 에서는 프로젝트 속성에서 build 탭으로 가서 allow unsafe code 에 체크해 주면 됨)
를 해야 한다.
주의 : stack allocation 은 C에서의 local 변수와 같다.
stack allocation으로 할당받은 변수를 변수의 scope 밖에서도 사용하려면 반드시 copy를 따로 해야 한다.
주의 : C#의 stack의 크기는 작다(1M정도) 그러니 여기다가 엄청 큰 데이터를 넣지는 말자.
햇갈리지 말아야 할 것은 메모리 관리를 할 필요가 없다는 점이다. (사실 할수도 없는듯??)
delete 같은거 해줘야 하는게 아닌지 고민하지 말자. 얘는 그냥 로컬변수다.
아래에 보면 장단점이 잘 정리가 되어있다.
Overview of Stack Allocation
Pros:
- Fast Allocation
- Fast Array Traversal
- No Need for Garbage Collection
Cons:
- Only Basic Types and Pointers Can Be Stack Allocated
- Contents Must be Copied to Be Used Out of the Current Scope
- Stack Memory is, By Default, Very Limited in Size ( One Megabyte )
- Unsafe Code Opens the Potential for Security and Stability Problems
stackalloc Keyword:
- Used For Dynamic Array Allocation
- Can Allocate Arrays of Any Unmanaged Type
- Bounds Checked
fixed Keyword:
- Used For Static Sized Arrays Inside Structs
- Only Available in .NET 2.0 and Newer
- Not Bounds Checked
Improving Performance Through Stack Allocation (.NET Memory Management: Part 2)
Articles in This Series
Part 1 – Basic Housekeeping
Part 2 – Improving Performance Through Stack Allocation
Part 3 – Increasing the Size of your Stack
Part 4 – Choosing the Right Garbage Collector Settings
Part 5 – Changing Your Garbage Collector Settings on the Fly
Introduction
In C#, when you create managed objects or arrays of value types, they are created on the Heap and you are passed back a reference to the memory in which that allocated object lives. This is normally a very good thing because it allows you to safely do what you need with it and have it be magically garbage collected when there are no longer any strong references. However, this process incurs a lot of overhead both at allocation time as well as during garbage collection.
The alternative to this is stack allocation. Except for a few exceptions in which the compiler is trying to do some fancy tricks or save you from yourself, references (pointers), structs and value types are kept on the stack. This makes sense because if all of these tiny objects had to be heap allocated and then garbage collected it would take a lot of extra overhead. If you are willing to use unsafe code you can leverage the stack to greatly enhance the performance of some types of applications.
When is it done for me?
Value types are always allocated on the stack:
int num = 10;
All unmanaged members of a struct will be kept on the stack.
struct TestStruct1
{
public byte y;
public double z;
}
TestStruct1 ts1 = new TestStruct1();
The following example is a managed struct. The struct and integer i will normally be kept on the stack while k will be a reference to an array allocated on the heap.
struct TestStruct2
{
public int[] k;
}
TestStruct2 ts2 = new TestStruct2();
ts2.k = new int[1024];
The compiler will also sometimes decide to put things on the stack on its own. I did an experiment with TestStruct2 in which I allocated it both an unsafe and normal context. In the unsafe context the array was put on the heap, but in the normal context when I looked into memory the array had actually been allocated on the stack.
Unsafe Code
In order to have control over stack allocation you need to execute your code in contexts marked as unsafe. You can do this by using the unsafe keyword at the class, method or code block level:
unsafe class Class1
{
…
}
static unsafe void Main(string[] args)
{
…
}
unsafe
{
…
}
You will also need to make sure the /unsafe compiler flag is enabled.
It is important to understand that unsafe code can open the door to security and stability problems. Before writing unsafe code for use in a production environment, make sure to read both the Security section of the C# developer’s guide and the section on Unsafe Code.
It is also important to note that libraries or applications with unsafe code can only be used in Full Trust environments. This is particularly an issue if you are writing a web application which will be deployed in an IIS context which you do not have control over.
The stackalloc keyword
C# has the stackalloc keyword which lets you force unmanaged type arrays to be allocated on the stack inside unsafe contexts:
int* ptr = stackalloc int[1024];
This will allocate a contiguous array of 1024 integers on the stack. Similarly, you can allocate an array of unmanaged structs on the stack as well:
TestStruct1* ptr2 = stackalloc TestStruct1[10];
This type of allocation is really fast, the garbage collector is never invoked and transversing the array has greatly reduced overhead. This is can be a huge win for performance minded applications. There is one big disadvantage that should be kept in mind however: because things allocated on the stack will go away when they go out of context, they must be copied if you want to use their contents outside of the current method.
The only case in which memory is bounds checked in unsafe code is with stackalloced memory. This constant checking does not come for free and so you may see even better performance when using the fixed keyword inside a stack allocated struct.
The fixed Keyword
.NET 2.0 and later have a keyword called fixed for defining fixed length arrays as part of a struct in unsafe contexts. Unlike using dynamic array allocation, a fixed length array will be considered as part of the struct instead of just a reference. It also has the added bonus of being an unmanaged type and so a struct which uses it will be stack allocated by default.
struct TestStructFixed
{
public fixed int k[1024];
}
TestStructFixed tsf = new TestStructFixed();
It is very important to note that arrays defined with the fixed keyword will do no bounds checking for you.
Overview of Stack Allocation
Pros:
- Fast Allocation
- Fast Array Traversal
- No Need for Garbage Collection
Cons:
- Only Basic Types and Pointers Can Be Stack Allocated
- Contents Must be Copied to Be Used Out of the Current Scope
- Stack Memory is, By Default, Very Limited in Size ( One Megabyte )
- Unsafe Code Opens the Potential for Security and Stability Problems
stackalloc Keyword:
- Used For Dynamic Array Allocation
- Can Allocate Arrays of Any Unmanaged Type
- Bounds Checked
fixed Keyword:
- Used For Static Sized Arrays Inside Structs
- Only Available in .NET 2.0 and Newer
- Not Bounds Checked
Additional Information
In this post I did not fully explore all of the differences between the stack and the heap. To explore these differences further, C# Corner has a set of fairly comprehensive set of articles on the topic.
'C#, .NET' 카테고리의 다른 글
int to byte[] , byte[] to int (0) | 2011.06.17 |
---|---|
Form application 과 Thread (0) | 2011.06.17 |
Window Message 를 직접 처리하기 (0) | 2011.06.17 |
정밀하게 시간측정 하기. (0) | 2011.06.17 |
virtual method 와 Interface (0) | 2011.06.17 |