자바는 입출력을 다루기 위한 InputStream, OutputStream을 제공한다. 스트림은 단방향으로만 데이터를 전공할 수 있어, 입력과 출력을 동시에 처리하기 위해 각각의 스트림이 필요하다.
입출력 스트림은 어떤 대상을 다루느냐에 따라 종류가 나뉜다. File을 다룰 땐 FileInputStream, FileOutputStream을 사용한다.
FileReader와 FileWriter는 문자 기반 스트림이다.
문자 기반 스트림은 문자 데이터를 다룰 때 사용하는데, 그 하위 클래스는 여러 종류의 인코딩과 자바에서 사용하는 유니코드(UTF-16) 간의 변환을 자동으로 처리한다.
일반적으로, 바이트 기반 스트림의 InputStream이 Reader로, OutputStream이 Writer로 대응된다.
FileReader는 인코딩을 유니코드로 변환하고, FileWriter는 유니코드를 인코딩으로 변환한다.
프로세스는 실행 중인 애플리케이션을 의미한다. 애플리케이션을 실행하면 운영체제로 부터 실행에 필요한 메모리를 할당받아 프로세스가 된다.
프로세스는 데이터, 컴퓨터 자원, 스레드로 구성되는데, 스레드는 데이터와 애플리케이션이 확고한 자원을 활용해 소스 코드를 실행한다. 즉, 스레드는 하나의 코드 실행 흐름이다.
자바 애플리케이션을 실행하면 가장 먼저 실행되는 메서드는 main
메서드다. 메인 스레드가 main
메서드를 실행시켜 준다. 메인 스레드는 main 메서드의 코드를 처음부터 끝까지 순차적으로 실행시키며, 코드의 끝을 만나거나 return문을 만나면 실행을 종료한다.
어떤 자바 애플리케이션의 소스 코드가 싱글 스레드로 작성되었다면, 그 애플리케이션이 실행되어 프로세스가 될 때 오로지 메인 스레드만 가지는 싱글 스레드 프로세스가 된다. 반면, 메인 스레드에서 또 다른 스레드를 생성하여 실행시킨다면 해당 애플리케이션은 멀티 스레드로 동작하게 된다.
하나의 프로세스는 여러 개의 스레드를 가질 수 있는데, 이를 멀티 스레드 프로세스라 한다.
여러 개의 스레드를 갖는 다는 것은 여러 스레드가 동시에 작업을 수행할 수 있음을 말하고, 이를 멀티 스레딩이라 한다.
멀티 스레딩은 하나의 애플리케이션 내에 여러 작업을 동시에 수행하는 멀티 태스킹을 구현하는 데 핵심적인 역할을 수행한다.
메인 스레드 외에 별도의 작업 스레드를 활용한다는 것은 작업 스레드가 수행할 코드를 작성하고, 작업 스레드를 생성해 실행하는 것이다.
스레드가 수행할 코드를 클래스 내부에 작성해줘야 하며, run()
메서드 내에서 스레드가 처리할 작업을 작성해야 한다.
JVM은 자바 프로그램을 실행시키는 도구다. 자바로 작성한 소스 코드를 해석해 실행하는 별도의 프로그램이다.
즉, JVM은 자바 프로그램과 운영체제 사이에서 일종의 통역가 역할을 수행한다.
JVM에 자바 프로그램이 로드되어 실행될 때 특정 값과 바이트코드, 객체, 변수 등과 같은 데이터들이 메모리에 저장되어야 한다. 런타임 데이터 영역이 바로 이러한 정보를 담는 메모리 영역이며, 크게 5가지 영역으로 구분된다.
스택은 일종의 자료구조다. 프로그램이 데이터를 저장하는 방식을 의미하는데, 프로그램이 데이터를 저장하는 방식은 여러가지이며 그 중 하나가 스택이라고 이해하면 된다.
스택은 LIFO 라는 키워드로 설명되는데, LIFO는 Last In First Out의 약자로 마지막에 들어간 데이터가 가장 먼저 나온다는 의미다.
프링글스를 생각해보자. 프링글스는 완벽한 스택의 형태를 갖고 있다.
프링글스의 뚜껑을 열고 감자칩을 꺼낼 때, 맨 아래에 있는 칩을 가장 먼저 꺼낼 수 있는가? 밑면을 뜯어내지 않는 이상, 일반적인 방식으로는 불가능하다.
프링글스처럼 가장 마지막에 들어온 데이터가 가장 먼저 나가는 구조(후입선출)를 스택이라 한다.
스택은 메서드가 호출되면 그 메서드를 위한 공간인 Method Frame이 생성된다. 메서드 내부에서 사용하는 다양한 값들이 있는데, 참조변수, 매개변수, 지역변수, 리턴값과 연산 시에 일어나는 값들이 임시로 저장된다.
이런 메소드 프레임은 스택에 호출되는 순서대로 쌓이고, 메서드의 동작이 완료되면 역순으로 제거된다.
JVM에는 단 하나의 Heap 영역이 존재한다. JVM이 작동되면 이 영역은 자동 생성되고 객체나 인스턴스 변수, 배열이 저장된다.
Person person = new Person();
new Person()
이 실행되면 Heap 영역에 인스턴스가 생성되고 인스턴스가 생성된 위치의 주소값을 person
에게 할당해준다. 이때 person
은 Stack 영역에 선언된 변수다.
우리가 객체를 다룬다는 것은 Stack 영역에 저장된 참조 변수를 통해 Heap 영역에 존재하는 객체를 다룬다는 의미다. Heap 영역은 실제 객체의 값이 저장되는 공간인 것이다.
자바에서는 가비지 컬렉션이란 메모리를 자동으로 관리하는 프로세스가 포함되어 있다.
가비지 컬렉션이랑 프로그램에서 더 이상 사용하지 않는 객체를 찾아 삭제, 제거해 메모리를 확보하는 것이다.
Person person = new Person();
person.setName("Kim");
person = null;
//가비지 발생
person = new Person();
person.setName("Lee");