JAVA) JAVA 메모리관리에 대해

백준우·2022년 12월 27일
0

Java & Spring

목록 보기
2/6
post-thumbnail
post-custom-banner

JAVA메모리 관리와 Garbage Collection에 대해서

1. JAVA의 메모리관리

  1. Stack
  2. Heap

들어가면서

  • 이전에 JavaScript의 구동방식을 살펴보면서 코드에 대한 이해도와 비동기 및 동기화 방식에 대해 시각이 넓어졌다. 그리고 덕분에 코드를 짤때 내가 적은 코드들이 어떻게 데이터를 관리하는지 머릿속으로 구상하면서 코드를 짤 수 있게되어 좀 더 심도 있고 깔끔한 코드관리가 가능했다.
  • 이 경험을 빗대어 이번에 JAVA를 시작하면서도 메모리관리를 살펴보면서 코드가 어떻게 구동되는지 살펴보려고 한다.


<출처 - https://dzone.com/articles/java-memory-management >

1. JAVA의 메모리관리

  1. Stack
  • 원시타입의 데이터가 할당되는 곳이다. 지역변수들은 Scope에따른 Visibility를 가진다.
  • 또는, heap영역에 할당된 Object타입의 데이터들의 참조를 위한 값들이 할당된다.
  • 데이터가 하나하나 순차적으로 저장되는 직선형 구조이다. (LIFO - Last In First Out 구조)
  • 우리가 스택에 데이터를 추출하고 삽입할땐 끝부분에만 접근이 가능하다.
  • JVM(JAVA Virtual Machine)에서 각각의 스레드는 1개의 스택을 가지고 모든 메소드를 트랙킹한다.
  • 메서드가 종료되는 "}"를 만나게되면 메서드내에서 선언된 지역변수는 stack에서 POP이 되면서 사라진다.
타입이름종류
정수타입byte , char , short , int
실수타입float , double
논리타입boolean
public class Main {
	 public static void main(String[] args) {
        int num = 1;
        num = setStack(num);
    }

    public static int setStack(int number){
        int element = number * 3;
        return ele;
    }
}
위의 코드를 예시로들었을때 메모리가 어떻게 관리되는지확인해보겠다.
  1. 먼저 num에 1이 할당된다.
  2. 다음으로 setStack() 메서드가 호출이 되고 argument로 num을 넘겨준다. 이때 스코프가 바뀌면서 기존에 main에 stack에 들어간 num은 더이상 사용할 수 없게된다. 그리고 바뀐 스코프에 따라 아래그림과 같이 Stack에 누적된다.
  3. 다음으로 setStack메서드안의 연산이 적용된다.
  4. 마지막으로 }로 setStack의 괄호가 닫히면서 기존에 적용된 지역변수들은 모두 POP되고 함수를 호출했던 시점으로 돌아가서 아래와 같은 상태가 된다.

    마지막에 num에 1이할당되어 있지만 3이 재할당 되면서 위와같은 상태가 되는거다.
    그리고 마지막으로 main의 메서드도 }를 만나면 안에 데이터들은 모두 POP되고 비어있는 Stack상태로 프로그램이 종료된다.
  1. Heap
  • Heap영역은 주로 긴 생명주기를 가지는 데이터들이 저장된다.
  • 쓰레드갯수와 상관없이 하나의 Heap영역만 존재한다.
  • Heap영역의 데이터들의 주솟값을 Stack에서 가지게 된다.
  • 배열타입, 열거타입 , 클래스 , 인터페이스를 가진다.
  • Class를 선언할때 "클래스 변수 = 클래스()"를 생각하면 Heap에 클래스를 저장하고 주솟값을 Stack에 변수로 저장한다고 생각하면 되겠다.
  • 참조하는 변수가 없다면 자동으로 힙 영역에서 제거 된다.
public static void main(String[] args) { 
	List<String> list = new ArrayList<>();
    list.add("one");
    list.add("two");   //  ====> 1번 상태 
    String result = sub(list)
    System.out.println(list); // ====> 3번 상태
}

public static String sub(List<String> mainList) {
	String element = mainList.get(0);
    mainList.add("three");
    return element; // ====> 2번 상태
}

위의 코드를 보면서 메모리가 어떻게 관리되는지 확인해보겠다.

1번상태)


위의 그림과 같이 list라는 stack에 Heap에 있는 List의 값의 위치가 할당되는구조이다.

2번상태)


위의 Stack에 설명한대로 Scope의 변경에따라 list변수에는 접근이 불가한 상태이다.
하지만 argument로 list를 받아와 같은 위치에 있는 List에 접근이 가능한것이다.

3번상태)

만약 3번상태인 System.out.println(list)에 결과값은 어떻게 될까?
같은 곳의 List를 수정했으니 안에값은 그대로 있을거다라고 생각하겠지만 틀렸다.
Scope가 변화됨과 동시에 할당된 "three"의 값도 pop으로 없어지게 되는것이다.

결과적으로 다음과 같은 값이 나타나게 되는것이다.

TIP) Static area(스태틱 메모리 영역)

  • JAVA는 크게 필드, 생성자, 메소드로 구성이 된다. 그중 필드 부분에서 선언된 변수는 정적변수와 멤버변수로 나뉘게 되는데 이때 Static이 붙는게 정적 변수이다.
  • 이때 Static은 프로그램이 시작부터 종료까지 쭉 메모리에 남아있게 되는것이고 나쁘게 말하면 무분별한 사용시 메모리를 빠르게 잡아먹지만
  • 이를 감안하고 사용만 잘한다면 지속적으로 사용되는 데이터를 static으로 두어 유용하게 사용할 수 있는것이다.

마치며 ...

  • 자바의 정확한 메모리 구성이 이해가니 코드를 읽으면서 데이터가 어떻게 흘러가는지 머릿속으로 그려지는게 보기좋다.

참고

profile
이게 되네?
post-custom-banner

0개의 댓글