티스토리 뷰
Goal
- 자바가 메모리를 어떻게 관리하는지 알아본다.
- 스택 메모리 영역과 힙 메모리 영역의 역할을 알아본다.
- 가비지 콜렉터의 역할과 필요한 이유를 알아본다
- 인스턴스와 힙메모리의 관계를 알아본다
- 상수풀에 대해 알아본다.
1. 스택 영역
- 함수 호출 시 생성되는 지역 변수와 매개 변수가 저장되는 영역.
- 스택 영역에 할당된 변수는 다른 메모리 영역과 다르게 함수 호출이 완료되면 사라짐.
- 늦게 할당된 변수의 메모리가 먼저 해제되므로 스택의 특징과 일치한다.
*scope : 스택에 저장되어있는 데이터 중 어떤 부분을 실행해야 할지를 나타내는 범위로, 스택의 저장 순서에 상관없이 자유롭게 넘나들며 코드를 실행시킨다.
*pop : 지역, 전역변수를 따져서 scope에 더이상 들어갈 수 없는 경우 pop을 통해 스택 영역에 담겨있는 자료를 삭제한다. ex) 메서드 내부에 선언된 변수는 메서드의 실행이 종료되면 더이상 사용할 수 없게 되고 스택 영역에서 사라짐.
2. heap 영역
- 참조변수가 참조하는 Object타입의 값들을 저장하고 있는 메모리 영역.
- scope에 상관없이(전역, 지역 상관없이) heap영역의 값을 참조하여 변형시킬 수 있다. (기본 자료형을 로컬 scope에서 변형시키려면 변수를 static으로 선언해야 하지만, heap영역의 값들은 바로 참조 가능)
* but
String 객체와 Wrapper class는 Immutable 하기 때문에, 한번 선언 된 이후 값이 바뀌지 않는다는 점을 유념해야 한다.
예를들어
public class prac {
public static void main(String[] args) {
String str = "Hello world"; // 가비지 값이 됨.
str += "2";
System.out.println(str);
}
}
위의 코드와 같이 참조변수 str이 "Hello world"를 참조하고, str에 "2"를 더해주는 작업을 할 때,
처음 str이 참조하고 있던 Hello world 값에 2를 더하여 Hello world2라는 String을 만들어주는게 아닌, Hellow world2라는 새로운 값을 초기화 하고 str이 참조하고 있는 변수가 초기화된 값을 참조하기 때문에 기존의 Hello world값은 주소를 읽은 가비지 값(Unreachable Object)이 된다.
즉, 새로운 값(Hello world2)이 heap영역에 생기게 되고, 스택 에는 str 참조변수가 그대로 남아있어, str은 heap에 생긴 새로운 값을 참조하게 되어 기존에 참조하고 있던 값(Hello world)은 가비지 값이 되는 것이다.
이를 처리하기 위해 가비지 콜렉터가 필요하다.
JVM의 Garbage Collector는 Unreachable Object를 우선적으로 메모리에서 제거하여 메모리 공간을 확보한다. Garbage Collection 과정은 Mark and Sweep 이라고도 한다.
(왜 불변객체를 사용할까? : 불변 객체는 멀티 스레드 프로그래밍에서도 유용하다. 데이터가 불변 객체에 저장돼 있다면 복수의 스레드에 의해서 특정한 스레드의 데이터가 변경될 우려없이 데이터에 접근할 수 있다. 즉, 배타 제어(mutual exclusion)를 할 필요가 없다. 쉽게 말해 불변 객체가 가변 객체보다 스레드 세이프(Thread-safe) 하다고 생각하면 된다. 불변객체 - 위키백과)
3. 인스턴스와 힙메모리
3-1 인스턴스
- 클래스로 부터 생성된 객체
- 힙 메모리에 맴버변수의 크기에 따라 메모리가 생성
- 클래스를 기반으로 new 키워드를 이용하여 생성자를 통해 여러 개의 인스턴스를 생성
- 참조 변수와 데이터 타입 정보는 Stack에 저장되고 해당 변수가 힙 메모리에 있는 인스턴스 값을 참조함.
* 상수 풀 (Constant Pool)
- String을 생성할 때, 일반적인 객체의 생성처럼 new를 이용하여 생성하는 것과 ""리터럴을 이용하여 생성하는 경우 2가지가 있다.
class ConstantTest {
public static void main(String[] args) {
String str1 = new String("Hello world");
String st2 = "Hello world";
}
}
- new를 이용해서 String 생성할 경우, 해당 객체는 새로 생기는 것이기 때문에 새로운 주소값을 갖는 인스턴스가 생성되어 참조변수에 저장된다
- ""리터럴을 이용하여 String을 생성할 경우, 생성된 인스턴스는 힙메모리 안에 존재하는 상수 풀 (Constant Pool)이라는 곳에 생성된다. 상수풀에 담긴 String 값들은 주소값이 공유 될 수 있다.
package sort.backjoon;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
String s1 = new String("hello");
String s2 = new String("hello");
String s3 = "hello";
String s4 = "hello";
String s5 = s1;
//상수 풀의 존재
if(s1 == s2) System.out.println("s1과 s2 주소값이 같음");
if(s2 == s3) System.out.println("s2과 s3 주소값이 같음");
if(s3 == s4) System.out.println("s3과 s4 주소값이 같음");
if(s5 == s1) System.out.println("s5과 s1 주소값이 같음");
if(s1.equals(s2)) System.out.println("s1과 s2 객체 내용이 같음");
if(s1.equals(s3)) System.out.println("s1과 s3 객체 내용이 같음");
}
}
- 위코드의 실행 결과는 ""리터럴로 선언하고 hello로 값이 같은 s3과 s4는 주소값이 동일한데 반해 hello로 값이 같지만 new로 생성한 s1과 s2는 각각 새로운 주소를 할당받아 주소값이 다른 결과를 확인할 수 있다.
- 상수풀을 이용할 경우 이미 생성된 스트링을 공유하기 때문에 메모리를 절약하는 효과가 있으며, 상수 풀의 내용에는 가비지콜렉터가 접근하지 않고 프로그램이 끝나면 삭제된다.
자료 참고 블로그
( https://yaboong.github.io/java/2018/05/26/java-memory-management/ )
* 자바 메모리 사용 한번에 이해되는 동영상
https://www.youtube.com/watch?v=dBRU_-eLvpU&list=PLq8wAnVUcTFWQ4TpRPZRa5nj1VwfyO7st&index=15
'Java > Java Basic' 카테고리의 다른 글
String[] args (Java) (0) | 2020.04.21 |
---|---|
BufferedReader, BufferWriter (Java) (0) | 2020.04.12 |
Java 객체 지향 프로그래밍 (생활코딩) (0) | 2020.02.28 |
copyOfRange(), copyOf() (Java) (0) | 2020.02.26 |
2차원 배열 (Two Dimensional Array) (0) | 2020.02.24 |
- 20200417
- 20200420
- 20200622
- 20200428
- 20200502
- 20201204
- 20200503
- 20200406
- 20200421
- chapter8
- 20200804
- 20200413
- 20200427
- 백준
- 20200423
- 20200424
- 20200510
- likelion
- 20200330
- 20200403
- 20200624
- 20200415
- 20200317
- 20200319
- 20200512
- chapter7
- 생활코딩리눅스
- 20200425
- 20200504
- 20200429
- Total
- Today
- Yesterday