>  기사  >  Java  >  Java의 힙, 스택 및 메모리 할당 상수 풀 분석

Java의 힙, 스택 및 메모리 할당 상수 풀 분석

巴扎黑
巴扎黑원래의
2017-08-01 10:56:351535검색

Java 메모리 할당에는 주로 다음 영역이 포함됩니다.

1. 레지스터: 프로그램에서 제어할 수 없습니다.

2. 스택: 기본 유형의 데이터와 객체에 대한 참조를 저장하지만 객체 자체는 스택에 저장되지 않습니다. 그러나 힙에 저장됨

3. 힙: new

4를 사용하여 생성된 데이터를 저장합니다. 정적 도메인: 개체에 static으로 정의된 정적 멤버를 저장합니다.

5. 상수 풀: 비 RAM(임의) 접근메모리) 저장공간 : 하드디스크 등 영구 저장공간

************************************ ****** ******************************

Java 메모리 할당의 스택  일부

함수의 기본 정의 유형 변수 데이터

객체 참조 변수 는 함수의 스택 메모리에 할당됩니다. 변수가 코드 블록에 정의되면 Java는 변수가 범위를 벗어날 때 변수에 대한 메모리 공간을 스택에 할당합니다. Java는 변수에 할당된 메모리 공간을 자동으로 해제하고 메모리 공간을 즉시 사용할 수 있습니다. 다른 목적으로 사용됩니다.

Java 메모리 할당의 힙힙 메모리는

new

에서 생성된 객체와 배열을 저장하는 데 사용됩니다. 힙에 할당된 메모리는 자바 가상 머신의 자동 가비지 컬렉터에 의해 관리됩니다. 힙에 배열이나 개체를 생성한 후 스택에 있는 변수의 값이 힙 메모리에 있는 배열이나 개체의 첫 번째 주소와 동일하도록 스택에 특수 변수를 정의할 수도 있습니다. 스택의 변수는 배열이나 개체에 대한 참조 변수가 됩니다. 참조 변수는 배열이나 개체에 이름을 지정하는 것과 같습니다. 그런 다음 스택의 참조 변수를 사용하여 프로그램의 힙에 있는 배열이나 개체에 액세스할 수 있습니다. 참조 변수는 배열이나 객체에 이름을 지정하는 것과 같습니다.

 참조 변수는 정의 시 스택에 할당되는 일반 변수입니다. 참조 변수는 프로그램이 해당 범위 외부에서 실행된 후 해제됩니다. 배열과 객체 자체는 힙에 할당됩니다. 배열이나 객체를 생성하기 위해 new를 사용하는 명령문이 있는 코드 블록 외부에서 프로그램이 실행되더라도 배열과 객체 자체가 차지하는 메모리는 해제되지 않습니다. 객체에 자신을 가리키는 참조 변수가 없으면 가비지가 되어 더 이상 사용할 수 없지만 여전히 메모리 공간을 차지하고 나중에 불확실한 시간에 가비지 수집기에 의해 수집(해제)됩니다. 이는 Java가 더 많은 메모리를 차지하는 이유이기도 합니다.

 

사실 스택의 변수는 힙 메모리의 변수를 가리킵니다. 이것은 Java의 포인터입니다!

상수 풀(Constant Pool)  상수 풀은 컴파일 과정에서 결정되어 컴파일된 .class 파일에 저장되는 일부 데이터를 말합니다. 코드에 정의된 다양한

기본 유형(예: int, long

등)과 객체 유형(예: 문자열 및 배열)을 포함하는 상수 값 ​​(최종) 외에도 텍스트 형식의 일부 기호 참조:

    클래스 및 인터페이스의 정규화된 이름
  1. 필드 이름 및 설명자
  2. 메서드 및 이름 및 설명자.
  3.  가상 머신은 로드된 각 유형에 대해 일정한 풀을 유지해야 합니다. 상수 풀은 직접 상수(문자열, 정수 및 부동 소수점 상수)와 다른 유형, 필드 및 메소드에 대한 기호 참조를 포함하여 이 유형에서 사용되는 순서화된 상수 세트입니다.

 문자열 상수의 경우 해당 값은 상수 풀에 있습니다. JVM의 상수 풀은 메모리에 테이블 형식으로 존재합니다. 문자열 유형의 경우 리터럴 문자열 값을 저장하는 데 사용되는 고정 길이 CONSTANT_String_info 테이블이 있습니다. 참고: 이 테이블은 기호가 아닌 리터럴 문자열 값만 저장합니다. . 이렇게 말하면 상수 풀에서 문자열 값의 저장 위치를 ​​명확하게 이해해야 합니다.

 

프로그램이 실행되면 힙이 아닌 메소드 영역에 상수 풀이 저장됩니다.

Heap and StackJava의 힙은 클래스(객체가 공간을 할당하는 런타임 데이터 영역)입니다. 이러한 객체는 new, newarray, anewarray 및 multianewarray와 같은 명령어를 통해 생성되며 프로그램이 필요하지 않습니다.

힙은 가비지 수집

을 담당합니다. 힙의 장점은 메모리 크기를 동적으로 할당할 수 있고수명을 컴파일러에 미리 알릴 필요가 없다는 것입니다. 런타임에 메모리를 동적으로 할당하면 Java의 가비지 수집기가 더 이상 사용되지 않는 데이터를 자동으로 수집하지만 단점은 런타임에 메모리를 동적으로 할당해야 하기 때문에 액세스 속도가 느리다는 것입니다.

 스택의 장점은 레지스터 다음으로 액세스 속도가 힙보다 빠르며, 스택 데이터를 공유할 수 있다는 점입니다. 하지만 스택에 저장되는 데이터의 크기와 수명을 결정해야 하기 때문에 유연성이 부족하다는 단점이 있습니다. 스택은 주로 몇 가지 기본 유형의 변수 데이터(int, short, long, byte, float, double, boolean, char)와 객체 핸들(참조)을 저장합니다. **************************************************** ******************

여기서 우리는 주로 스택, 힙 및 상수 풀에 관심을 가집니다.

스택 및 상수 풀의 개체를 공유할 수 있습니다

.

힙 개체는 공유할 수 없습니다. 스택에 있는 데이터의 크기와 수명 주기는 데이터에 대한 참조가 없으면 사라질 수 있습니다. 힙에 있는 개체는 가비지 수집기에 의해 재활용되므로 크기와 수명 주기를 결정할 필요가 없으며 유연성이 뛰어납니다.

문자열 메모리 할당:

문자열의 경우 해당 객체 참조는 스택

에 저장됩니다. 컴파일 중에 생성된 경우(큰따옴표로 직접 정의) 상수 풀에 저장됩니다. , 런타임 중에 결정되면(새 항목이 나오는 경우) 힙

에 저장됩니다. 같음 문자열의 경우 상수 풀에는 항상 하나의 복사본만 있고 힙에는 여러 개의 복사본이 있습니다. 다음 코드와 같습니다:

        String s1 = "china";
        String s2 = "china";
        String s3 = "china";

        String ss1 = new String("china");
        String ss2 = new String("china");
        String ss3 = new String("china");


여기서는 문자열("china"로 가정)이 생성되면 먼저 상수 풀로 이동하여 다음을 수행합니다. 이미 존재하는지 확인합니다. "china" 개체가 없으면 상수 풀에 문자열 개체를 만든 다음 힙의 상수 풀에 "china" 개체의 복사본을 만듭니다.

 이것은 인터뷰 질문이기도 합니다: Strings=newString(“xyz”);는 얼마나 많은 개체를 생성합니까? 하나 또는 둘, 상수 풀에 "xyz"가 없으면 2개입니다.

 .class 파일에 존재하는 상수 풀은 런타임 중에 JVM에 의해 로드되어 확장될 수 있습니다. String의 intern() 메소드는 상수 풀을 확장하는 메소드로, String 인스턴스 str이 intern() 메소드를 호출하면 Java는 상수 풀에 동일한 유니코드를 가진 문자열 상수가 있는지 확인하여 반환합니다. 그렇지 않은 경우 상수 풀에 str과 동일한 유니코드 문자열을 추가하고 해당 참조를 반환합니다.

다음 코드:

        String s0= "kvill";   
        String s1=new String("kvill");   
        String s2=new String("kvill");   
        System.out.println( s0==s1 );     
        s1.intern();   
        s2=s2.intern(); //把常量池中"kvill"的引用赋给s2   
        System.out.println( s0==s1);   
        System.out.println( s0==s1.intern() );   
        System.out.println( s0==s2 );
출력 결과:


false

false
true
true
문자열 상수 풀 문제의 몇 가지 예:

【1】
String a = "ab"= "b"= "a" +== b)); = "ab" String bb = "b"= "a" +== b)); = "ab" String bb == "a" +== b));   "b"
분석:


  [1]에서 문자열의 "+" 연결에 문자열 참조가 있으므로 JVM은 문자열 참조를 갖습니다. 참조 값은 프로그램 컴파일 중에 결정될 수 없습니다. 즉, "a" + bb는 프로그램 실행 중에만 동적으로 할당될 수 있으며 b에 연결한 후에 새 주소를 할당할 수 있습니다. 따라서 위 프로그램의 결과는 거짓입니다.

[2]와 [1]의 유일한 차이점은 bb 문자열이 최종 수정된다는 것입니다. 최종 수정된 변수의 경우 컴파일 타임에 상수 값의 로컬 복사본으로 구문 분석되어 자체 상수 풀에 저장됩니다. 바이트코드 스트림에 포함됩니다. 따라서 이때 "a" + bb와 "a" + "b"의 효과는 동일합니다. 그러므로 위 프로그램의 결과는 참이다.

【3】JVM은 컴파일 중에 문자열 참조 bb의 값을 결정할 수 없습니다. 프로그램 실행 중에 메서드를 호출한 후에만 메서드의 반환 값과 "a"가 동적으로 연결되고 주소가 b에 할당되므로 위의 내용은 다음과 같습니다. 프로그램의 결과는 거짓입니다.

결론:

  문자열은 특수 패키징 클래스이며 해당 참조는 스택에 저장되며 객체 내용은 생성 방법(상수 풀 및 힙)에 따라 결정되어야 합니다. 일부는 이미 컴파일 중에 생성되어 저장됩니다. 문자열 상수 풀에서 일부는 런타임에 생성되며 new 키워드를 사용하여 힙에 저장됩니다.

기본형 변수와 상수의 메모리 할당

 기본형 변수와 상수는 변수와 참조가 스택에 저장되고, 상수는 상수 풀에 저장됩니다.

다음 코드와 같습니다:

        int i1 = 9;        int i2 = 9;        int i3 = 9;        final int INT1 = 9;        final int INT2 = 9;        final int INT3 = 9;


  编译器先处理int i1 = 9;首先它会在栈中创建一个变量为i1的引用,然后查找栈中是否有9这个值,如果没找到,就将9存放进来,然后将i1指向9。接着处理int i2 = 9;在创建完i2的引用变量后,因为在栈中已经有9这个值,便将i2直接指向9。这样,就出现了i1与i2同时均指向9的情况。最后i3也指向这个9。

成员变量和局部变量在内存中的分配

  对于成员变量和局部变量:成员变量就是方法外部,类的内部定义的变量;局部变量就是方法或语句块内部定义的变量。局部变量必须初始化。 形式参数是局部变量,局部变量的数据存在于栈内存中。栈内存中的局部变量随着方法的消失而消失。 成员变量存储在堆中的对象里面,由垃圾回收器负责回收。   如以下代码:


class BirthDate {    private int day;    private int month;    private int year;    public BirthDate(int d, int m, int y) {
        day = d;
        month = m;
        year = y;
    }    // 省略get,set方法………}public class Test {    public static void main(String args[]) {        int date = 9;
        Test test = new Test();
        test.change(date);
        BirthDate d1 = new BirthDate(7, 7, 1970);
    }    public void change(int i) {
        i = 1234;
    }
}

  对于以上这段代码,date为局部变量,i,d,m,y都是形参为局部变量,day,month,year为成员变量。下面分析一下代码执行时候的变化:    

  1. main方法开始执行:int date = 9; date局部变量,基础类型,引用和值都存在栈中。

  2. Test test = new Test();test为对象引用,存在栈中,对象(new Test())存在堆中。 

  3. test.change(date);  i为局部变量,引用和值存在栈中。当方法change执行完成后,i就会从栈中消失。

  4. BirthDate d1= new BirthDate(7,7,1970); d1为对象引用,存在栈中,对象(new BirthDate())存在堆中,其中d,m,y为局部变量存储在栈中,且它们的类型为基础类型,因此它们的数据也存储在栈中。day,month,year为成员变量,它们存储在堆中(new BirthDate()里面)。当BirthDate构造方法执行完之后,d,m,y将从栈中消失。 

  5. main方法执行完之后,date变量,test,d1引用将从栈中消失,new Test(), new BirthDate()将等待垃圾回收。

위 내용은 Java의 힙, 스택 및 메모리 할당 상수 풀 분석의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.