Stack vs Heap 사이의 메모리 할당 기본 사항과 혼동되고 있습니다. 표준 정의에 따라 (사물은 모두가 말한다), 모든 값 유형 에 할당 얻을 것이다 스택 및 참조 로 이동합니다 유형 힙 .
이제 다음 예를 고려하십시오.
class MyClass
{
int myInt = 0;
string myString = "Something";
}
class Program
{
static void Main(string[] args)
{
MyClass m = new MyClass();
}
}
이제 메모리 할당은 C #에서 어떻게 발생합니까? MyClass
(즉, m
) 의 객체가 힙에 완전히 할당됩니까? 즉, int myInt
그리고 string myString
모두가 힙에 갈 것인가?
또는 객체가 두 부분으로 나뉘어 두 메모리 위치 인 스택 및 힙에 할당됩니까?
답변
m
힙에 할당되며 myInt
. 기본 유형 (및 구조체)이 스택에 할당되는 상황은 메서드 호출 중이며 스택에서 로컬 변수를위한 공간을 할당합니다 (더 빠르기 때문). 예를 들면 :
class MyClass
{
int myInt = 0;
string myString = "Something";
void Foo(int x, int y) {
int rv = x + y + myInt;
myInt = 2^rv;
}
}
rv
, x
은 ( y
는) 모두 스택에 있습니다. myInt
힙 어딘가에 있습니다 ( this
포인터 를 통해 액세스해야 함 ).
답변
구현 세부 사항으로 객체가 할당되는 위치에 대한 질문을 고려해야합니다 . 객체의 비트가 정확히 어디에 저장되어 있는지는 중요하지 않습니다. 객체가 참조 유형인지 값 유형인지는 중요 할 수 있지만 가비지 수집 동작을 최적화해야하기 전까지는 객체가 저장 될 위치에 대해 걱정할 필요가 없습니다.
현재 구현에서는 참조 유형이 항상 힙에 할당되지만 값 유형 은 스택에 할당 될 수 있지만 반드시 그런 것은 아닙니다. 값 유형은 참조 유형에 포함되지 않고 레지스터에 할당되지 않은 박싱되지 않은 비 이스케이프 로컬 또는 임시 변수 인 경우에만 스택에 할당됩니다.
- 값 유형이 클래스의 일부인 경우 (예제에서와 같이) 힙에있게됩니다.
- 박스형이면 힙에있게됩니다.
- 배열에 있으면 힙에서 끝납니다.
- 정적 변수이면 힙에서 끝납니다.
- 클로저에 의해 캡처되면 힙에있게됩니다.
- 반복기 또는 비동기 블록에서 사용되는 경우 힙에서 끝납니다.
- 안전하지 않거나 관리되지 않는 코드로 만든 경우 모든 유형의 데이터 구조 (스택 또는 힙일 필요는 없음)에 할당 될 수 있습니다.
내가 놓친 것이 있습니까?
물론 주제에 대한 Eric Lippert의 게시물에 링크하지 않았다면 나는 실망 할 것입니다.
- 스택은 구현 세부 사항, 1 부
- 스택은 구현 세부 사항, 2 부
- 그리고 아마도 가장 좋은 것 : 가치 유형에 대한 진실
답변
“모든 VALUE 유형이 스택에 할당됩니다”는 매우 잘못되었습니다. 구조체 변수 는 메서드 변수로 스택에 있을 수 있습니다 . 그러나 유형의 필드는 해당 유형 을 사용합니다 . 필드의 선언 유형이 클래스 인 경우 값은 해당 개체의 일부로 힙에 있습니다. 필드의 선언 유형이 구조체 인 경우 필드는 해당 구조체가 있는 모든 곳에서 해당 구조체의 일부입니다 .
비록 방법 변수가 있다 이러한 경우 힙에있을 캡처 (λ / 아논-방법), 또는 (예를 들어) 반복기 블록의 일부.
답변
훌륭한 설명 :
답변
스택
는
stack
저장 메모리 블록local variables
과parameters
. 스택은 함수가 입력 및 종료됨에 따라 논리적으로 확장 및 축소됩니다.
다음 방법을 고려하십시오.
public static int Factorial (int x)
{
if (x == 0)
{
return 1;
}
return x * Factorial (x - 1);
}
이 메서드는 재귀 적이므로 자신을 호출합니다. 메소드가 입력 될 때마다, 새로운 INT는 스택에 할당 하고, 때마다 메소드 종료는 INT는 해제됩니다 .
더미
- 힙은
objects
(예reference-type instances
🙂 상주 하는 메모리 블록입니다 . 새 개체가 생성 될 때마다 힙에 할당되고 해당 개체에 대한 참조가 반환됩니다. 프로그램이 실행되는 동안 새 개체가 생성되면 힙이 채워지기 시작합니다. 런타임에는 힙에서 개체를 주기적으로 할당 해제하는 가비지 수집기가 있으므로 프로그램이 실행되지 않습니다Out Of Memory
. 객체는 그 자체로 참조되지 않는 즉시 할당 해제 대상이됩니다alive
.- 힙은 또한
static fields
. 힙에 할당 된 객체 (가비지 수집 될 수 있음)와 달리these live until the application domain is torn down
.
다음 방법을 고려하십시오.
using System;
using System.Text;
class Test
{
public static void Main()
{
StringBuilder ref1 = new StringBuilder ("object1");
Console.WriteLine (ref1);
// The StringBuilder referenced by ref1 is now eligible for GC.
StringBuilder ref2 = new StringBuilder ("object2");
StringBuilder ref3 = ref2;
// The StringBuilder referenced by ref2 is NOT yet eligible for GC.
Console.WriteLine (ref3); // object2
}
}
위의 예에서는 변수 ref1이 참조하는 StringBuilder 객체를 만든 다음 해당 내용을 작성합니다. 그 StringBuilder 객체는 이후에 그것을 사용하는 것이 없기 때문에 즉시 가비지 수집에 적합합니다. 그런 다음 ref2 변수가 참조하는 또 다른 StringBuilder를 만들고 해당 참조를 ref3에 복사합니다. 해당 시점 이후에 ref2가 사용되지 않더라도 ref3은 동일한 StringBuilder 객체를 유지하여 ref3 사용을 완료 할 때까지 수집 대상이되지 않도록합니다.
값 유형 인스턴스 (및 개체 참조)는 변수가 선언 된 모든 위치에 있습니다. 인스턴스가 클래스 유형 내의 필드 또는 배열 요소로 선언 된 경우 해당 인스턴스는 힙에 있습니다.
답변
간단한 조치
값 유형은 THE STACK에서 확장 될 수 있으며, 일부 미래주의 데이터 구조에 할당 할 수있는 구현 세부 사항입니다.
따라서 값과 참조 유형이 작동하는 방식을 이해하는 것이 더 낫습니다. 값 유형은 값으로 복사됩니다. 즉, 값 유형을 FUNCTION에 매개 변수로 전달할 때 자연적으로 복사되는 것보다 전체 새 사본이 있음을 의미합니다. .
참조 유형은 참조로 전달됩니다 (참조가 일부 향후 버전에서 주소를 다시 저장한다는 점을 고려하지 마십시오. 다른 데이터 구조에 저장 될 수 있음).
그래서 당신의 경우
myInt는 참조 유형을 벗어난 클래스에서 캡슐화 된 int이므로 ‘THE HEAP’에 저장 될 클래스의 인스턴스에 연결됩니다.
ERIC LIPPERTS가 작성한 블로그를 읽을 수 있습니다.
답변
객체가 생성 될 때마다 힙이라는 메모리 영역으로 이동합니다. int 및 double과 같은 기본 변수는 로컬 메서드 변수 인 경우 스택에 할당되고 멤버 변수 인 경우 힙에 할당됩니다. 메서드에서 로컬 변수는 메서드가 호출 될 때 스택으로 푸시되고 메서드 호출이 완료되면 스택 포인터가 감소합니다. 다중 스레드 응용 프로그램에서 각 스레드는 자체 스택을 가지지 만 동일한 힙을 공유합니다. 이것이 힙 공간에서 동시 액세스 문제를 방지하기 위해 코드에서주의를 기울여야하는 이유입니다. 스택은 스레드로부터 안전하지만 (각 스레드에는 자체 스택이 있음) 코드를 통한 동기화로 보호되지 않는 한 힙은 스레드로부터 안전하지 않습니다.
이 링크는 http://www.programmerinterview.com/index.php/data-structures/difference-between-stack-and-heap/ 도 유용합니다 .