Posts 학원 #17일차: 예외와 에러, outOfMemory, Program argument, JVM argument
Post
Cancel

학원 #17일차: 예외와 에러, outOfMemory, Program argument, JVM argument

오늘은 배운 내용이 많아서 특히 중요한 부분은 다른 포스트에 나눠 작성하였다.

메서드 호출

매개변수의 데이터 타입이 기본형이면 메서드를 실행하면서 변경한 값이 반영되지 않습니다. 매개변수의 데이터타입이 참조형이면 메서드를 실행하면서 변경한 값이 반영됩니다. 이에 대한 자세한 설명은 “메서드 호출: 기본형과 참조형 매개변수의 차이점” 포트스에서 다루었습니다.

JVM 메모리 구조

메서드 호출을 이해하기 위해서는 우선 Java Virtual Machine이 어떻게 동작하는 지 알아야 합니다. “JVM 메모리: Method Area, Stack, Heap” 포스트에서 간략하게 해당 내용을 정리하였습니다.

예외(Exception)와 에러(Error)

지금까지 저는 exception과 error를 구분 없이 그냥 ‘오류’로 받아들여 왔는데, 이 둘 사이에는 큰 차이점이 있었습니다.

  • 예외(Exception): 개발자가 구현한 로직에서 발생한다. 발생하더라도 수습할 수 있는 비교적 덜 심각한 오류를 말한다. 프로그래머가 적절히 코드를 작성해주면 비정상적인 종료는 막을 수 있다(발생할 상황을 미리 예측하여 처리할 수 있다.)
  • 에러(Error): 시스템에 비정상적인 상황이 생겼을 때 발생한다. 시스템 레벨에서 발생하기 때문에 심각한 수준의 오류이고, 개발자가 미리 예측하여 처리할 수 없다. 따라서 애플리케이션에서 오류에 대한 처리를 신경쓰지 않아도 된다. 시스템에 변화를 주어 문제를 처리해야 하는 경우가 일반적이다.

예외 처리를 공부하면서 자세하게 공부할 예정이니 이 정도로 정리하고 넘어가겠습니다.

OutOfMemoryError: Java heap space

Heap 공간에 새로운 개체를 생성할 수 없는 경우 발생한다.

1
2
3
4
5
6
7
8
9
10
11
12
public static void main(String[] args) throws Exception {
    ArrayList list = new ArrayList();
    while (true) {
        list.add(createArray());
        Thread.currentThread().sleep(2000);
    }
}

static int[] createArray() {
    System.out.println(".");
    return new int[10000000];
}

위의 코드는 createArray() 메서드를 통해 Heap에 길이가 1000000인 배열을 만들고 만들어진 배열의 주소값을 ArrayList에 하나씩 저장하는 프로그램이다.

만약 배열을 무한정 생성만 하고 그 주소값을 로컬 변수에 저장하지 않는다면, 해당 배열은 heap에 메모리는 차지하고 있지만 아무런 참조 변수도 가지지 않는 상태, 즉 가비지(garbage) 가 된다. 이렇게 생성된 가비지는 JVM이 한가하거나, 메모리가 부족할 때 Garbage Collector를 동작시켜 처리한다.

그러나 위 코드는 Heap에 무한정으로 배열을 만들고, 이 배열의 참조변수 또한 있기 때문에 가비지가 아니다. 따라서 메모리가 부족하더라도 가비지 컬렉터가 처리하지 못한다. 따라서 메모리를 일정 수준 이상으로 넘어가게 되면 Heap 메모리가 부족한 상태, Exception in thread_name: java.lang.OutofMemoryError: Java heap space 메시지를 띄우며 프로그램이 강제 종료된다.

Recursive Call / Stack Overflow

재귀호출과 스택 오버플로우에 대해서는 따로 포스팅을 올렸다.

main() 메서드

Java Virtual Machine이 클래스를 실행할 때 main() 메서드를 호출한다. 메인 메서드는 반드시 다음과 같은 method signature(function prototype)을 가져야 한다.

1
2
3
public static void main(String[] 변수명은상관없다) {
    System.out.println("main()");
}

Program argument

프로그램 아규먼트는 JVM을 프로그램을 실행할 때 넘겨주는 값이다.

1
$ java -cp ./main/bin com.hayeon17kim.java.Monica arg1 arg2

클래스 파일을 실행할 때 주는 위 명령어에서 arg1과 arg2가 프로그램 아규먼트이다.

1
2
3
4
5
6
7
8
public static void main(String[] args) {
    for (String value : args) {
        System.out.printf("[%s]\n", value);
    }
}
// 결과
// [arg1]
// [arg2]

프로그램 아규먼트는 스트링 배열에 담겨 main()를 호출할 때 넘어온다. 프로그램 아규먼트는 공백을 기준으로 문자열을 잘라서 배열을 만든다. 아규먼트가 없으면 빈 배열이 넘어온다. 그런 후 main()를 호출할 때 그 배열의 주소를 넘겨준다.

JVM argument

JVM 아규먼트는 JVM에게 전달하는 값이다.

1
$ java -cp ./main/bin -D이름1=-D이름2=값 패키지명.클래스명

System.getProperty()메서드를 사용하여 JVM 아규먼트의 값을 꺼낼 수 있다.

1
2
3
4
5
String value1 = System.getProperty("이름1");
String value2 = System.getProperty("이름2");

System.out.println(value1);
System.out.println(value2);

JVM 전체 프로퍼티 목록 가져오기

1
2
3
4
5
6
7
8
java.util.Properties props = System.getProperties();

java.util.Set keySet = props.keySet();

for (Object key : keySet) {
    String value = System.out.getProperty((String) key);
    System.out.printf("%s=%s\n", key, value);
}
This post is licensed under CC BY 4.0 by the author.

:coffee: Recursive Call(재귀호출), Stack Overflow

:coffee: [Java] 입력과 출력

Loading comments from Disqus ...