Java 기본 요소 배열이 스택 또는 힙에 저장됩니까?


85

다음과 같은 배열 선언이 있습니다.

int a[];

다음 a은 기본 int유형 의 배열입니다 . 이 어레이는 어디에 저장됩니까? 힙 또는 스택에 저장됩니까? 이것은 primitve 유형 int이며 모든 기본 유형은 힙에 저장되지 않습니다.


38
그것은 배열이 아닙니다. 배열에 대한 참조입니다. 참조 자체는 클래스 또는 개체의 구성원 인 경우 힙에 저장되고 메서드의 지역 변수 인 경우 스택에 저장 될 수 있습니다. 기본 유형은 클래스 또는 객체의 구성원 인 경우 힙에 저장할 수 있습니다.
uncleO

답변:


143

gurukulki가 말했듯이 힙에 저장됩니다. 그러나 귀하의 게시물은 "원시가 항상 스택에 산다"라는 신화를 전파하는 선의의 사람 때문에 오해를 제안했습니다. 이것은 사실이 아닙니다. 지역 변수 는 스택에 값이 있지만 모든 기본 변수가 지역 변수는 아닙니다.

예를 들어 다음을 고려하십시오.

public class Foo
{
    int value;
}
...

public void someOtherMethod()
{
    Foo f = new Foo();
    ...
}

자, 어디에 f.value살고 있습니까? 신화는 그것이 스택에 있음을 암시하지만 실제로는 새로운 Foo객체 의 일부이며 힙 1에 있습니다. ( f자체 의 값은 참조이며 스택에 있습니다.)

여기서부터는 배열을 쉽게 수행 할 수 있습니다. 배열을 많은 변수로 생각할 수 있습니다. 따라서 다음 new int[3]과 같은 형식의 클래스를 갖는 것과 비슷합니다.

public class ArrayInt3
{
    public readonly int length = 3;
    public int value0;
    public int value1;
    public int value2;
}

1 사실, 이것은 이것보다 더 복잡합니다. 스택 / 힙 구분은 대부분 구현 세부 사항입니다. 실험적인 JVM 일 수있는 일부 JVM은 객체가 메소드에서 "이스케이프"되지 않는시기를 알려주고 전체 객체를 스택에 할당 할 수 있습니다. 그러나 신경 쓰도록 선택하면 개념적 으로 힙에 있습니다.


1
Java의 "탈출 분석"정보 : blog.juma.me.uk/2008/12/17/objects-with-no-allocation-overhead JDK 6 업데이트 14의 조기 액세스 릴리스 이후에 존재한다고 말합니다. JDK 6 업데이트 23 이후 기본적으로 활성화
귀도

배열이 public static final이면 변경됩니까? 그러면 상수 풀의 일부가되어야하지 않습니까?
Malachiasz 2014

@Malachiasz : 아니요. 배열은 절대 상수가 아닙니다.
Jon Skeet 2014

@JonSkeet는 : 제가 알고 자바 라이브러리의 모든 버전에서 모든는 Stringa로 백업됩니다 char[]. 나는 리터럴 문자열이 공개 상수 풀에 저장되어 있다고 믿습니다. GC 최적화의 경우 이는 백업 어레이도 마찬가지로 저장되어야 함을 의미합니다 (그렇지 않으면 백업 어레이가 수집에 적합한 GC주기 동안 상수 풀을 스캔해야 함).
supercat 2014-06-08

@supercat : 네, 말이됩니다. 그러나 직접 선언 한 배열 은 상수 풀의 일부로 끝나지 않습니다.
Jon Skeet

37

힙에 저장됩니다.

배열은 자바의 객체이기 때문입니다.

편집 : 만약 당신이

int [] testScores; 
testScores = new int[4];

이 코드는 컴파일러에게 "4 개의 정수를 담을 배열 객체를 만들고라는 참조 변수에 할당합니다 testScores. 또한 각 int요소를 0으로 설정 합니다. 감사합니다." 라고 말하는 것으로 생각 하세요 .


2
그리고 testScores (힙의 배열을 가리킴)라는 참조 변수가 스택에 있습니다.
Zaki

11
-g컴파일러에 옵션을 제공하는 경우에만 코드에 "Thanks"라고 표시됩니다 . 그렇지 않으면 멀리 최적화됩니다.
mob

1
@mob 이것이 유일한 코드라고 가정하고 있습니다. 이 두 줄이 실제로 배열을 사용하는 더 큰 프로그램의 일부라고 가정하는 것이 좋습니다.
Code-Apprentice

22

그 자체로 원시가 아닌 원시 유형의 배열입니다. 경험상 좋은 규칙은 새 키워드가 관련 될 때 결과가 힙에 있다는 것입니다.


18

이 주제에 대해 실행 한 몇 가지 테스트를 공유하고 싶었습니다.

1000 만 크기의 배열

public static void main(String[] args) {
    memInfo();
    double a[] = new double[10000000];
    memInfo();
}

산출:

------------------------
max mem = 130.0 MB
total mem = 85.0 MB
free mem = 83.6 MB
used mem = 1.4 MB
------------------------
------------------------
max mem = 130.0 MB
total mem = 130.0 MB
free mem = 48.9 MB
used mem = 81.1 MB
------------------------

보시다시피 사용 된 힙 크기는 10m * sizeof (double) 인 ~ 80MB만큼 증가합니다.

하지만 double 대신 Double을 사용한다면

public static void main(String[] args) {
    memInfo();
    Double a[] = new Double[10000000];
    memInfo();
}

출력은 40MB로 표시됩니다. 이중 참조 만 있고 초기화되지 않았습니다.

Double로 채우기

public static void main(String[] args) {
    memInfo();
    Double a[] = new Double[10000000];      
    Double qq = 3.1d;
    for (int i = 0; i < a.length; i++) {
        a[i] = qq;
    }
    memInfo();
}

여전히 40MB. 그들은 모두 동일한 Double 객체를 가리 키기 때문입니다.

대신 double로 초기화

public static void main(String[] args) {
    memInfo();
    Double a[] = new Double[10000000];
    Double qq = 3.1d;
    for (int i = 0; i < a.length; i++) {
        a[i] = qq.doubleValue();
    }
    memInfo();
}

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space

a[i] = qq.doubleValue();

다음과 같다

a[i] = Double.valueOf(qq.doubleValue());

이는

a[i] = new Double(qq.doubleValue());

매번 새로운 Double 객체를 생성하기 때문에 힙을 날려 버립니다. Double 클래스 내의 값이 힙에 저장되어 있음을 보여줍니다.


1
memInfo () pls의 코드 세부 사항을 붙여 넣을 수 있습니까? :)
hedleyyan

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.