ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Java] 메모리 stack,heap
    java 2021. 5. 31. 18:42

    스레드를 공부하면서 공유 객체에 대해 공부할 필요가 생겼다. 

     

    인터넷의 자료들을 바탕으로 매우 간단하게 정리하였다.

     

    읽기전에 알아야할 내용들

    멤버변수, static변수(클래스 변수), 지역변수 

    클래스 로딩이 언제 수행되는가. 클래스 로딩시 static변수 초기화 작업 및 static초기화 블럭 수행

    참조 값을 저장하는 참조형 변수 , 실제 값을 저장하는 primitive변수

     

     

    https://velog.io/@woo00oo/%EB%B3%80%EC%88%98%EC%9D%98-%EC%A2%85%EB%A5%98%EC%99%80-%EB%A9%94%EB%AA%A8%EB%A6%AC-%EA%B5%AC%EC%A1%B0

    메소드 영역( 클래스 로딩시 static변수가 저장되는 곳)

     

    힙 영역( 모든 객체가 저장되는 곳.  객체내부의 인스턴스 변수또한 힙에 저장됨, 동적 메모리, 주로 긴 시간 존재해야 할 데이터가 저장됨, GC의 대상, 메모리의 낮은 곳에서 높은 곳 방향으로 메모리 할당이 이루어짐)

     

    스택 영역( 메서드 연산시 잠깐 잠깐 올라갈 변수를 올리는 곳, 메모리의 높은 곳에서 낮은 곳 방향으로 메모리 할당이 이루어짐, 메서드 호출시 메서드 스택프레임이 생성되며 여기에 지역변수가 포함되고 메서드 종료시 지역변수가 소멸되며 메서드 스택프레임이 없어진다. )


    Stack

     

    1. 메서드 내부(메서드 매개변수 포함)

    2. {}내부

    3. 생성자 블록(생성자 매개변수 포함)

    4. 인스턴스, 클래스 초기화 블록 

    1,2,3,4에서 선언된 변수는 지역변수라고 한다.

     

    지역변수가 primitive타입(기본형. int, long, double...등등)이면 직접 값이 저장되고

    객체 타입이면 객체의 주소인 reference가 저장됨

     

    1,2,3,4의 경우중 1. 메서드 내부(main메서드 내부)를 예로 들었다.

    main메서드{
    	int i=3;
       	Object obj=new Object(); //오브젝트 객체가 heap의 500번지에 저장되어있다 가정
    }

    main메서드가 호출되면 메서드 연산에 필요한 지역변수가 stack프레임에 올라간다.

    i-3, obj-500 이라는 값을 가진 상태로 stack에 저장되어 있다. main메서드가 종료될때 소멸된다.

    stack에서 쌓이고(push) 빠지는(pop)방법은 좋은 블로그들을 참고할 것.

     

    I=3(실제 값)   heap
    obj=500(주소값) 500번지: new Object()
    main메서드스택 프레임  
    전체 stack

    Heap

     

    모든 객체는 heap에 저장된다. (배열,String도 객체)

    GC의 대상(가비지 컬렉터)이 된다.

     

    클래스의 필드중 인스턴스 변수가 heap에 저장된다.

    완전히 확실하진 않지만 여기저기 뒤져보니 맞는 것 같다.

    https://stackoverflow.com/questions/23550385/where-are-instance-variables-of-an-object-stored-in-the-jvm

     

    Where are instance variables of an Object stored in the JVM?

    Is an instance variable of an object in Java stored on the stack or method area of the JVM? Also, do we have different instance variable for multiple threads? If it is stored in method area how is

    stackoverflow.com

     

    Stack and heap are the memories allocated by the OS to the JVM that runs in the system.Stack is a memory place where the methods and the local variables are stored. (variable references either primitive or object references are also stored in the stack). Heap is a memory place where the objects and its instance variable are stored.

     

    Heap은 객체와 객체의 인스턴스 변수가 저장되는 메모리이다. 라고한다.

     

    public class JavaMemoryStructureTest {
    	
    	public static void main(String[] args) {
    		myStaticMethod(); // = JavaMemoryStructureTest.myStaticMethod();
    		
    	}
    	
    	public static void myStaticMethod() {
    		MyClass mc=new MyClass();
    	}
    }
    
    class MyClass {
    	private Object obj=new Object();
    
    	MyClass() {
    		super();
    	}
    }
    

    main메서드가 호출되면 args지역변수가 생성되고( 보통 프로그램 실행과 함께 아무 스트링도 넣어주지 않으므로 길이가 0인 String배열이고 그 String배열이 저장되어있는 heap의 공간 주소를 참조하고 있겠다)

     

    myStaticMethod가 호출되면

    new MyClass()로 생성된 객체는 heap에 생성 (저장된 곳이 heap의 500번지라고 가정)

    stack에 지역변수 mc가 생성되고 500이라는 주소값을 참조하고 있다.

    mc-500

     

    new MyClass() 인스턴스 초기화 작업중 멤버변수 obj 초기화중 new Object()는 객체이므로 무조건 heap에 저장되고 (저장된 곳이 heap의 800번지라고 가정)

    obj는 인스턴스 멤버이므로 800이라는 값을 가지고 heap에 생성된다.

     

    인스턴스 변수가 obj가 Heap에 저장되는 것에 대해 약간의 의문점이 있긴 했는데 조금 생각해보면 맞는것 같다.

    myStaticMethod메서드가 종료되면 지역변수 mc가 사라지고 new MyClass()를 참조하고 있는 것이 없어 GC의 대상이되는데 그 과정에서 멤버인 obj-800과 new Object() 같이 사라져야 하니 인스턴스 멤버변수를 heap에다 저장되게 해놓은 것이다. 이 예제에서는 알랑뚱땅 new MyClass()요거 한줄하고 메서드 종료가 되어 바로 사라지게 되는데 new MyClass가 살아있으면 인스턴스 멤버도 같이 살아있어야 하니 같은 공간에 두는 것이 타당하다고 생각되어진다.

     

    원래 주제로 넘어가서 myStaticMethod가 종료되면 지역변수 mc가 소멸되고 mc가 소멸되어 new MyClass()로 생성된 객체또한 참조될 수 없어 GC에 의해 소멸된다. new MyClass()가 소멸되면 멤버변수인 obj도 소멸되고 obj도 소멸되니 new Object()또한 참조될 수 없어 소멸된다.

     

    main메서드가 종료되어 지역변수 args가 소멸된다. args가 소멸되며 빈 스트링 배열또한 GC의 대상이 되어 소멸된다.

     

     

    Method영역

    클래스가 어떻게 생겨먹은 놈인지 조상이 뭔지 접근제한자 뭐를 가졌는지 클래스 정보를 가지고 있다. 

    클래스 로딩과 함께 static멤버 변수, static메서드가 저장된다. 클래스 로딩은 프로그램 시작과 함께 모든 클래스를 올리지 않고 코드에서 new 클래스()나 클래스.static메서드() 를 만날때 로딩이 이루어진다. 클래스 로딩은 클래스마다 한번만 수행한다. 클래스 로딩시 static멤버 변수 초기화, static초기화 블럭이 한번만 수행됨

     

    Java8이후 MetaSpace공간으로 이동되었다.라고 한다. 

    클래스 로딩 후 ~ JVM종료전까지 사라지지 않는다. 


    정리한 내용을 간단하게 요약하고 예제를 보자

    객체놈들은 무조건 heap에 저장된다.

    지역변수는 stack에 저장된다.

    클래스의 인스턴스 변수는 heap에 저장된다.

    클래스의 static 변수는 Method영역(heap)에 저장된다. 

    public class JavaMemoryStructureTest {
    	
    	public static void main(String[] args) {
    		myStaticMethod(); // = JavaMemoryStructureTest.myStaticMethod();
    		
    		
    	}
    	
    	public static void myStaticMethod() {
    		MyClass mc=new MyClass();
    		System.out.println("mc: "+System.identityHashCode(mc)); //798154996
    		System.out.println("mc.obj: "+System.identityHashCode(mc.obj)); //681842940
    		System.out.println("MyClass.str: "+System.identityHashCode(MyClass.str)); //1392838282
    	}
    }
    
    class MyClass {
    	
    	private int a=1;
    	private static int b=2;
    	
    	//private로 지정하고 getter,setter를 지정해야하는데 설명 편의상
    	//public으로 지정하였다.
    	public Object obj=new Object();
    	public static String str= new String("hello");
    	
    	MyClass() {
    		super();
    	}
    }

    System.identityHashCode(Object object)메서드는 고유한 객체마다 무조건 다른 값을 반환한다.

    실제 메모리 주소가 이 메서드에 의해 숫자 값으로 변환되지만 편의상 변환된 이값을 메모리 주소라고 가정하자.

     

    main메서드에서 myStaticMethod를 호출하면 new Class()가 호출되어 클래스 정보를 먼저 올리게 되어 클래스 로딩이 먼저이루어진다. 클래스 로딩과 함께 인스턴스 변수 생성자작업 이전에 static변수 작업을 먼저하게 된다.

     

    +)클래스 로딩

    new 클래스(); , 클래스.static메서드; 호출시 클래스 로딩이 이루어진다. 클래스 로딩은 하나의 클래스에 한번만 이루어진다. 

     

    main(){

    new 클래스(); //여기서 최초 한번 클래스 로딩

    new 클래스();

    }

     

    main(){

    클래스.static메서드(); //여기서 최초 한번 클래스 로딩

    new 클래스();

    }

     

    다시 이어서

    static 변수는 Heap의 Method영역에 생성된다.

    static 멤버 b는2를 가지고 Method영역에 생성되고

    new String("hello")는 객체이므로 heap의 1392838282에 생성되고 

    static 멤버 str은 1392838282를 가지고 Method영역에 생성된다.

     

    인스턴스 변수 생성 및 초기화 작업이 이루어져 a=1을 가지고 heap에 생성됨

    new Object()역시 객체이므로 heap의 681842940공간에 생성되고 obj는 인스턴스 변수이므로 heap에 생성되며 참조값 681842940를 가진다.

     

    이후 생성자 작업을 거쳐 생성된 마이클래스 객체는 heap의 798154996에 저장되고

     

    mc는 이 주소값을 가지고 stack에 생성된다.

     


     

     

     

     

     

     

     

    'java' 카테고리의 다른 글

    [Java] Mac주소 Hex String 변환  (0) 2022.10.28
    [Java] String.format  (0) 2022.09.07
    [Java] 익명 클래스 초기화 블록  (0) 2022.08.25
    [Java] Comparator,Comparable구현시 주의할 점  (0) 2022.07.13
    까먹은 것들 정리  (0) 2021.12.25

    댓글

Designed by Tistory.