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.