프리미티브 필드는 어디에 저장됩니까?
원시 필드는 인스턴스화 된 오브젝트의 일부로서 저장되는 곳 . 이것이 어디에 있는지 생각하는 가장 쉬운 방법은 힙입니다. 그러나 항상 그런 것은 아닙니다. Java 이론 및 실습에 설명 된대로 : 도시 성능 범례는 다음 과 같이 다시 방문했습니다 .
JVM은 이스케이프 분석이라는 기술을 사용하여 특정 객체가 전체 수명 동안 단일 스레드에 국한되어 있고 해당 수명이 주어진 스택 프레임의 수명에 의해 제한되어 있음을 알 수 있습니다. 이러한 객체는 힙 대신 스택에 안전하게 할당 될 수 있습니다. 또한 작은 객체의 경우 JVM이 할당을 완전히 최적화하고 객체의 필드를 레지스터로 호이스트 할 수 있습니다.
따라서 "객체가 만들어지고 필드도 있습니다"라는 말 외에는 무언가가 힙이나 스택에 있는지 말할 수 없습니다. 작고 수명이 짧은 개체의 경우 '개체'가 메모리에 존재하지 않고 대신 필드를 레지스터에 직접 배치 할 수 있습니다.
이 논문은 다음과 같이 끝납니다.
JVM은 놀랍게도 개발자 만 알 수 있다고 생각했던 것을 알아내는 데 능숙합니다. JVM이 사례별로 스택 할당과 힙 할당을 선택할 수 있도록함으로써 프로그래머가 스택에 할당할지 힙에 할당할지 고민하지 않고도 스택 할당의 성능 이점을 얻을 수 있습니다.
따라서 다음과 같은 코드가있는 경우 :
void foo(int arg) {
Bar qux = new Bar(arg);
...
}
(가) 어디에서 ...
허용하지 않는 qux
그 범위를 떠나, qux
수 대신 스택에 할당 될 수있다. 가비지 수집이 필요하지 않기 때문에 실제로 VM에서 승리합니다. 범위를 벗어나면 사라집니다.
Wikipedia의 이탈 분석 에 대한 추가 정보 . IBM의 Escape Analysis for Java에 대한 논문을 기꺼이 파고 드는 사람들을 위해 . C # 세계에서 온 사람들에게는 스택이 구현 세부 사항 이며 Eric Lippert의 가치 유형 에 대한 진실을 읽을 수 있습니다. . .Net 서적이 스택 대 힙 메모리 할당에 대해 이야기하는 이유는 무엇입니까? 이것도 들어갑니다.
스택과 힙의 이유
힙에
그렇다면 왜 스택이나 힙이 있습니까? 범위를 벗어나는 물건의 경우 스택이 비쌀 수 있습니다. 코드를 고려하십시오 :
void foo(String arg) {
bar(arg);
...
}
void bar(String arg) {
qux(arg);
...
}
void qux(String arg) {
...
}
매개 변수도 스택의 일부입니다. 힙이없는 경우 스택의 전체 값 세트를 전달합니다. 이것은 "foo"
작은 문자열에는 적합하지만 누군가가 그 문자열에 큰 XML 파일을 넣으면 어떻게 될까요? 각 호출 스택에 전체 큰 문자열을 복사합니다 - 그리고 그것은 매우 낭비입니다.
대신, 생명체가 다른 범위 (다른 범위로 전달되고 다른 사람이 유지 관리중인 구조 등)에있는 것을 힙이라고하는 다른 영역에 배치하는 것이 좋습니다.
스택에
스택이 필요 하지 않습니다 . 가설 적으로, (임의의 깊이로) 스택을 사용하지 않는 언어를 작성할 수 있습니다. 내가 젊었을 때 배운 오래된 BASIC은 그렇게 했으므로 8 레벨의 gosub
호출 만 할 수 있었고 모든 변수는 전역 적이었습니다. 스택은 없었습니다.
스택의 장점은 범위에 존재하는 변수가있을 때 해당 범위를 벗어나면 해당 스택 프레임이 팝된다는 것입니다. 실제로 존재하는 것과 존재하지 않는 것을 단순화합니다. 프로그램은 다른 절차 인 새 스택 프레임으로 이동합니다. 프로그램이 프로 시저로 돌아가고 현재 범위를 확인하는 절차로 돌아갑니다. 프로그램이 프로 시저를 떠나 스택의 모든 항목이 할당 해제됩니다.
이것은 실제로 코드를 위해 런타임을 작성하는 사람이 스택과 힙을 사용하는 것을 쉽게 만듭니다. 단순히 코드로 작업하는 많은 개념과 방법으로 언어로 코드를 작성하는 사람이 코드를 명확하게 생각할 수 없습니다.
스택의 특성은 또한 조각화 될 수 없음을 의미합니다. 메모리 조각화 는 힙의 실제 문제입니다. 몇 개의 객체를 할당 한 다음 가비지가 중간 객체를 수집 한 후 다음으로 큰 객체를 할당 할 공간을 찾으십시오. 엉망입니다. 대신 스택에 물건을 넣을 수 있다는 것은 그 일을 처리 할 필요가 없다는 것을 의미합니다.
가비지 수집 된 경우
무언가가 가비지 수집되면 사라집니다. 그러나 이미 잊어 버렸기 때문에 가비지 수집 만됩니다. 프로그램의 현재 상태에서 액세스 할 수있는 프로그램의 객체에 대한 참조가 더 이상 없습니다.
이것이 가비지 수집을 매우 단순화 한 것임을 지적하겠습니다. 많은 가비지 수집기가 있습니다 (Java 내부에서도-다양한 플래그 ( docs ) 를 사용하여 가비지 수집기를 조정할 수 있습니다 . 이들은 다르게 동작하며 각 작업이 수행되는 방식의 뉘앙스는이 답변에 대해 너무 깊습니다. Java Garbage Collection Basics 는 그 중 일부가 어떻게 작동하는지 더 잘 알 수 있습니다.
즉, 스택에 무언가가 할당되면 일부로 가비지 수집되지 않습니다 System.gc()
. 스택 프레임이 튀어 나올 때 할당이 해제됩니다. 무언가가 힙에 있고 스택의 무언가에서 참조 된 경우 해당 시점에 가비지 수집되지 않습니다.
이것이 왜 중요한가?
대부분의 전통. 작성된 교재와 컴파일러 클래스 및 다양한 비트 문서는 힙과 스택에 대해 많은 부분을 차지합니다.
그러나 오늘날의 가상 머신 (JVM 및 이와 유사한)은 프로그래머에게이를 숨기려고 많은 노력을 기울였습니다. 스토리지 공간을 적절하게 늘리기보다는 그 이유 를 알아야 할 필요가 없다면 , 그다지 중요하지 않습니다.
개체가 어딘가에 있고 개체가 존재 하는 적절한 시간 동안 정확하고 빠르게 액세스 할 수있는 위치에 있습니다. 스택이나 힙에 있으면 실제로 중요하지 않습니다.