본문 바로가기
Programming/Java

[JAVA] heap, stack, static 메모리 구조

by 우공80 2022. 8. 18.
728x90

Java의 각 객체는 각각 다른 메모리 영역에 로드가 됩니다.
보통은 신경 쓸 일이 적으나, 간혹 이 부분을 고려하지 않아서 오류가 발생하므로 기본적인 개념은 정리가 필요합니다.
한번 정리 안 하면 두고두고 헷갈리게 됩니다. (제가 그래서 지금 이 글을 쓰면서 개념을 정리하는 중입니다.)

Java의 메모리 영역은 다음과 같이 3가지입니다.

Stack, Heap, Method(Static)


하나씩 정리해 보겠습니다.

Stack 영역

Stack 영역은 기본 자료형(int, double, byte, long, boolean 등)에 해당되는 지역변수, 매개변수 등이 할당되는 영역입니다. 즉 임시로 사용하는 변수나 정보를 저장하는 영역입니다. 따라서 method가 호출될 때 생성되고, method 실행이 종료되면 제거됩니다.

Heap 영역

Heap 영역은 참조형 인스턴스가 할당되는 영역입니다. "new" 로 인스턴스가 생성되는 시점에 Heap 영역에 만들어지게 됩니다. Heap 영역은 위에서 설명한 Stack 영역을 통해서만 접근이 가능하고, GC가 정리할 때까지 남아있게 됩니다.
하나의 클래스로부터 여러개의 인스턴스가 만들어지고 각각 다른 주소를 할당받게 됩니다.

Method(Static) 영역

Method영역 혹은 Static 영역이라고도 부르고, 전역 변수와 static으로 선언된 멤버 변수를 할당합니다. static 변수는 인스턴스가 heap 메모리에 할당되지 않아도 class가 정의만 되면 메모리에 로드되고(즉 프로그램이 실행될 때), 해당 클래스의 모든 인스턴스가 공유하게 됩니다. (이 것이 싱글턴 패턴으로 이어지게 됩니다. )

java 메모리 영역



Static은 인스턴스 생성과 무관하게 할당이 되므로 개념적으로 사용할 수 없는 곳이 있는데요.
예를 들어 내부클래스 사용 시에는 사용할 수 없습니다.

아래 예제를 보시면 내부클래스에서 static변수를 사용하면 에러가 납니다.
OutClass가 생성될때 InClass도 정의되기 때문에, static변수나 메서드를 사용할 수 없습니다.

class OutClass {

	private int num = 10;
	private static int sNum = 20;
	private InClass inClass;
	
	public OutClass(){
		inClass = new InClass(); // 내부 클래스 생성
	}
	
	class InClass{
		
		int inNum = 100;
		//static int sInNum = 200;  //에러 남
		
		void inTest(){
			System.out.println("OutClass num = " +num + "(외부 클래스의 인스턴스 변수)");
			System.out.println("OutClass sNum = " + sNum + "(외부 클래스의 스태틱 변수)");
			System.out.println("InClass inNum = " + inNum + "(내부 클래스의 인스턴스 변수)");
		}
		
	    //static void sTest(){  //에러 남
	    	
	    //}
		
	}
	
	public void usingClass(){
		inClass.inTest(); //내부 클래스 변수를 사용하여 메서드 호출하기
	}
}

public class InnerTest {

	public static void main(String[] args) {
		OutClass outClass = new OutClass();
		System.out.println("외부 클래스 이용하여 내부 클래스 기능 호출");
		outClass.usingClass();    // 내부 클래스 기능 호출
	    System.out.println();
	    
		OutClass.InClass inClass = outClass.new InClass();   // 외부 클래스를 이용하여 내부 클래스 생성
		System.out.println("외부 클래스 변수를 이용하여 내부 클래스 생성");
		inClass.inTest();
	}

}

따라서 이런 경우에는 아래와 같이 내부 클래스 자체를 static으로 선언해서 사용해야 합니다.
그리고 꼭 static변수나 메서드를 사용하지 않더라도 내부 클래스에서 외부 클래스 참조가 없는 경우에는 static으로 선언하는 것이 좋습니다. static으로 선언하지 않는 경우 내부 클래스와 외부 클래스는 암묵적으로 연결되고 내부 클래스에서 연결을 관리하므로 메모리를 차지한다고 합니다.(생성도 느림). 그리고 가장 치명적인 것이, 이로 인해 외부 클래스가 GC대상에서 제외되어 메모리 누수 원인이 된다고 합니다

class OutClass {

	private int num = 10;
	private static int sNum = 20;
	private InClass inClass;
	
	public OutClass(){
		inClass = new InClass(); // 내부 클래스 생성
	}
	
	class InClass{
		
		int inNum = 100;
		//static int sInNum = 200;  //에러 남
		
		void inTest(){
			System.out.println("OutClass num = " +num + "(외부 클래스의 인스턴스 변수)");
			System.out.println("OutClass sNum = " + sNum + "(외부 클래스의 스태틱 변수)");
			System.out.println("InClass inNum = " + inNum + "(내부 클래스의 인스턴스 변수)");
		}
		
	    //static void sTest(){  //에러 남
	    	
	    //}
		
	}
	
	public void usingClass(){
		inClass.inTest(); //내부 클래스 변수를 사용하여 메서드 호출하기
	}
	
	static class InStaticClass{
		
		int inNum = 100;
		static int sInNum = 200;
		
		void inTest(){   //정적 클래스의 일반 메서드
			//num += 10;    // 외부 클래스의 인스턴스 변수는 사용할 수 없음.
			System.out.println("InStaticClass inNum = " + inNum + "(내부 클래스의 인스턴스 변수 사용)"); 
			System.out.println("InStaticClass sInNum = " + sInNum + "(내부 클래스의 스태틱 변수 사용)");
			System.out.println("OutClass sNum = " + sNum + "(외부 클래스의 스태틱 변수 사용)");
		}
		
		static void sTest(){  // 정적 클래스의 static 메서드
			//num += 10;   // 외부 클래스의 인스턴스 변수는 사용할 수 없음.
			//inNum += 10; // 내부 클래스의 인스턴스 변수는 사용할 수 없음
			
			System.out.println("OutClass sNum = " + sNum + "(외부 클래스의 스태틱 변수 사용)");
			System.out.println("InStaticClass sInNum = " + sInNum + "(내부 클래스의 스태틱 변수 사용)");
			
		}
	}	
}

public class InnerTest {

	public static void main(String[] args) {

	   .....
	   	
		//외부 클래스 생성하지 않고 바로 정적 내부 클래스 생성
		OutClass.InStaticClass sInClass = new OutClass.InStaticClass();  
		System.out.println("정적 내부 클래스 일반 메서드 호출");
		sInClass.inTest();
		System.out.println();
		
		System.out.println("정적 내부 클래스의 스태틱 메소드 호출");
		OutClass.InStaticClass.sTest();
	}

}

 

 

참고자료

패스트캠퍼스 - Java & SpringBoot로 시작하는 웹 프로그래밍
[Java] JVM 구조와 메모리 영역 - Method, Heap, Stack Area
[JAVA/자바] 메모리 구조(static, stack, heap)
기계인간 John Grib
728x90

댓글