Java

Perillamint (토론 | 기여)님의 2015년 4월 22일 (수) 04:58 판 (→‎단점: GC overhead)

Java는 썬 마이크로시스템즈(현재 오라클에 합병)에서 개발한 다중 플랫폼 객체지향 프로그래밍 언어이다.

설계 목표

Java 는 다음과 같은 목표를 따라 설계되고 구현되었다.[1]

  • Simple, Object-oriented and Familiar
  • Robust and Secure
  • Architecture Neutral and Portable
  • High Performance
  • Interpreted, Threaded, and Dynamic

특징

가상머신

일반적인 컴파일을 거치는 언어와 다르게, Java는 우선 컴파일러에서 바이트 코드라는 가상머신을 위한 이진 코드로 컴파일한다. 그후 자바 프로그램이 실행될 때, 가상머신에서 인터프리터 방식으로 이를 해석하여 실행 플랫폼에 맞는 기계어로 변환한다. 이로서 다중 플랫폼을 구현하였다.

객체지향

설계 목표에 따라 Java는 객체지향으로 구현되었다. 객체의 설계를 담고 있는 클래스를 작성하고, 이를 실제로 사용할 때는 클래스에 기반한 객체를 만들어서 사용한다. C++ 와 다르게 Java의 상속은 다중 상속이 아니다. Java 의 상속은 단 하나의 부모(Parent) 클래스만을 허용한다. 대신 인터페이스를 도입하여 C++ 보다 간략하지만 다중 상속이 가지고 있는 복잡성과 문제 발생 가능성을 줄이고 보다 쓰기 쉬운 형태로 구현되었다.

가비지 컬렉션(GC)

자바는 프로그래머에게 메모리 관리를 맡기지 않는다. 프로그래머가 생성하고, 이를 직접 해제하는게 아니라, 가상머신에서 프로그램을 잠시 멈춘후 사용하지 않는 객체를 제거한다. 이는 프로그래머의 수고를 덜어주었지만, 반대로 중간에 프로그램이 멈춰서 사용자의 불만을 초래하기도 한다.

예외 처리

사실 제일 불편한 게 이거라 카더라

자바에서 예외는 일단 막고 봐야 한다. 다른 언어에선 필요한 경우 예외처리를 한다면, 자바는 예외 처리를 하고 필요한 경우 조치를 취한다고 생각하면 된다.[2] 안 그러면 컴파일러가 "이거이거 예외처리 해야됨" 하고 오류를 내뿜는다. 그래서 보통 자바코드에선 try-catch 문을[3] 굉장히 빈번하게 볼 수 있다. try-catch 를 당장 완벽하게 구현하기 싫거나 현재 개발하는 부분에서 굳이 예외처리를 할 필요가 없을 경우, 메서드 선언부에 throws Exception 을 붙이면 대부분 컴파일이 된다. 이것을 적용할 수 없는 경우는 손에 꼽을 정도로 적기 때문에 딱히 불편하다고 할 수 없다.

Java 문법 중 클래스에 정의된 메서드가 예외(Exception)를 발생할 수 있음을 알리는 throws 키워드가 존재한다. throws 로 발생가능한 예외가 정의된 메서드를 사용할 경우, 예외 처리를 해주거나, 예외가 발생했을 경우 해당 메서드의 외부(메서드를 호출한 클래스) 쪽으로 던져주도록 처리하지 않으면 컴파일 타임에서 오류가 발생한다. 이는 컴파일 타임 수준에서 발생 가능한 오류를 점검하여 보다 안정적인 프로그램을 작성하도록 도와주는 기능이다. 개발 초기 단계에서는 보통 이를 대충 throw 만 하면서 프로토타이핑을 하지만, 완성 단계에 이르기 전까지 예외 발생 시 적절하게 처리를 하도록 try-catch 를 사용해 예외처리를 구현하게 된다.

ArrayIndexOutOfBoundsException, NullPointerException 같은 실행 시 발생할 수 있는 예외(Runtime Exception)는 컴파일러가 점검하지 않는다.

장점

안정성

가상머신 위에서 돌기 떄문에 자바로 만들어신 프로그램은 다른 언어로 작성된 프로그램 대비 컴퓨터와 같이 저승으로 승천하는 경우가 드물다. 하지만 다른 언어로 작성된 라이브러리를 Java Native Interface(JNI), Java Native Access(JNA) 등을 통해 끌어다 쓰는데 해당 라이브러리에서 심각한 오류가 발생하면 확실하게 맛이 가면서 뻗을 수도 있다.

다양한 라이브러리

기본적으로 다중플랫폼을 위하여 프로그램 제작에 필요한 대부분'의 클래스 및 라이브러리가 내장되어 있다. 외관은 둘째치고...

1995년에 자바가 등장하고, 전 세계적으로 널리 쓰이기 시작하면서 매우 방대한 라이브러리가 등장했으며, 인터넷을 통해 체계적으로 관리되는 Maven 중앙 저장소를 통해 약 10만종, 100만개[4]의 다양한 라이브러리를 인터넷만 연결되면 매우 손쉽게 끌어다 쓸 수 있다.

다중 플랫폼

인터프리터로 처리되는 자바의 특성상 다중 플랫폼을 지원한다. 현재 자바 인터프리터가 있는 OS 플랫폼은 윈도우, OS X, 우분투, 페도라 및 그 외 리눅스유닉스 계열[5], 심지어 블랙베리, 피처폰, 그외 임베디드 플랫폼에서도 자바를 사용할 수 있다. 최근에는 Raspberry PI 에서 구동할 수 있는 가상머신도 등장했다.[6]

단점

느린 속도

C같은 언어들은 기계어로 번역해서 바로 실행할 수 있는데, 바이트코드는 인터프리터를 거쳐서 실행되는 방식이기 때문에 기계어로 컴파일되어 실행되는 언어에 비해 느릴 수 밖에 없다. 특히 가상머신의 초기 기동 속도 때문에 최초 실행 시 매우 느린듯한 인상을 준다. 그러나 JIT 등의 기술을 도입해 실행속도를 향상시키려는 노력이 꾸준히 진행되었으며, 같은 로직을 수행하는 코드를 실행했을 때 필요한 시간은 C++ 대비 평균적으로 2배 정도까지 따라잡았다. 물론 일반적인 인터프리터 언어 대비 실행 속도는 당연히 훨씬 빠르다.

대량의 메모리 점유

간단한 코드를 실행하더라도 가상머신이 제대로 기동되기 때문에, 기계어 기반으로 실행되는 다른 언어 대비 메모리를 많이 소모하는 경향이 있다. 그리고 한 번 가상머신이 메모리를 점유하면, 실제로는 사용하고 있지 않아도 운영체제에 반환되지 않는다. 그래서 VMware 같은 가상 PC 프로그램 제작업체에서는 가상 머신을 위해 따로 제작된 여유 메모리 반환 프로그램과 라이브러리를 제공하는 경우도 있다.

GC 오버헤드

자바는 오브젝트가 버려질 경우, 해당 오브젝트를 바로 해제하지 않고, GC가 트리거되었을 때 해제하게 된다. 이 GC 트리거는 비결정적이며, GC 과정이 CPU-intensive 하므로, 어플리케이션은 불규칙적인 성능 저하를 겪게 된다.

주석

<references>

  1. 1.2 Design Goals of the Java™ Programming Language, Oracle, 1999, 조회일 2015-04-20
  2. 일부 RuntimeException의 경우 제외 왜 RuntimeException만 제외인건데
  3. 예외처리를 할 때 사용하는 코드이다.
  4. 2015년 4월 기준
  5. 안드로이드는 자바를 사용하긴 하나 사정이 다른데 그 이유는 안드로이드는 달빅 바이트코드를 사용하기 때문에 자바 바이트코드를 실행할 수 없다.
  6. 애초에 자바의 목적이 가전제품에서 돌아갈 수 있도록 하는 것이었다고 한다.