Category: Java

자바 프로그래밍에 대해 정리한 카테고리.

Windows JDK 1.8 Portable

최근에(2017년 11월) JAVA 9 가 발표 되었다. 이와 관련해서 이미 JAVA 9로 많은 소프트웨어가 포팅되고 배포되고 있다. 대표적으로 자바 개발 도구인 이클립스의 경우 최신버전은 JAVA 9 에서 매우 잘 동작 한다.

하지만 여전히 많은 소프트웨어가 JAVA 8 을 필요로 한다. 한 시스템에서 JDK 를 두가지 버전을 설치하는게 썩 좋아보이지 않다. 시스템에서 JAVA 9 를 메인으로 하고 JAVA 8은 포터블하게 설치해서 사용하면 얼마나 좋을까?

이 문서는 Windows 에 JDK 1.8 을 포터블 제작에 대한 것이다.

환경

  • Windows 10 64bit
  • JDK 1.8 u152
  • 7-zip 64bit

JDK 1.8 의 포터블 제작을 위한 환경은 위와 같다. 압축 프로그램이면 아무거나 다 되는거 아니냐 하겠지만 7-Zip 을 권장 한다.

압축 해제

다운받은 JDK 1.8 u152 설치 파일을(exe) 오른쪽 클릭한 후에 압축 해제한다.

JDK 1.8 u152 압축해제

압축을 해제하고 나후 디렉토리를 펼치면 위와같이 나온다.

tools.zip 파일

포터블 JDK 의 핵심은 바로 tools.zip 이다. 이 파일에는 java 의 실행파일, 라이브러리 파일등이 들어 있다. 문제는 이 파일이 안보이는데, JAVA_CAB10 디렉토리에 111 파일이 보인다. 이 파일을 압축 해제한다.

tools.zip

위 파일을 압축 해제하면 드디어 익숙해 보이는 파일들이 보인다.

tools.zip 압축해제

문제는 이걸 그대로 사용할 수가 없다는 것이다. 이 안에 많은 파일들이 *.pack 인채다.  cmd 창에서 tools.zip 압축해제한 디렉토리로 이동한 후에 다음과 같이 해준다.

그러면 다음과 같이 pack 파일이 jar 파일로 변경된다.

pack 파일을 jar로 변환.

src.zip 파일

JDK 1.8 의 소스 파일인데, 이는 다음과 같이 110 파일을 압축 해제하면 된다.

src.zip 파일

src.zip 파일을 tools.zip 압축 해제했던 디렉토리에 넣어준다.

COPYRIGHT 파일

JDK 에 COPYRIGHT 파일이 있어야 한다. 이는 다음과 같은 디렉토리에 112 파일을 압축해제하면 나온다.

JDK 1.8 COPYRIGHT 파일

압축해제해 나온 COPYRIGHT 파일을 tools.zip 압축해제한 디렉토리에 넣는다.

JDK 1.8 Portable

tools.zip 압축해제하고 pack 파일을 jar 로 전환하고 src.zip, COPYRIGHT 파일을 작성해 tools 압축해제한 디렉토리로 옮겨놨다.

이제 이 tools 디렉토리를 JDK 1.8 로 바꾸고 적당한 디렉토리로 옮겨서 사용하면 된다.

JDK 1.8 Portable

 

참고

  • https://portableapps.com/node/53015
  • https://techtavern.wordpress.com/2014/03/25/portable-java-8-sdk-on-windows/

 

아주 심플한 자바 웹 애플리케이션

이중화 시스템을 구축하면 WAS 서버의 헬스 체킹을 하기 위한 웹애플리케이션 페이지가 필요할 때가 있다. AWS ELB 가 대표적으로 ELB 뒤에 WAS 서버가 있을 경우에 HTTP를 이용한 헬스 체킹을 위해 웹애플리케이션의 페이지가 필요하게 된다.

보통은 Product 웹프로그램에 AWS ELB 헬스체킹을 위한 페이지를 넣을 수도 있지만 별도의 웹애플리케이션을 작성하는게 더 좋다.

이 문서는 이러한 환경에서 헬스체킹을 위한 아주 심플한 자바 웹 애플리케이션을 작성하는 법에 대해서 기술 한다.

디렉토리 구조

기본적으로 웹 애플리케이션의 기본 디렉토리는 다음과 같다.

  • META-INF/MANIFEST.MF
  • index.jsp
  • WEB-INF/web.xml

위 디렉토리와 파일을  jar 를 이용해서 war 파일로 압축해 배포하면 된다. 이때 Context Root 는 war 파일 이름이 된다.

META-INF/MANIFEST.MF

위 파일은 war 파일의 정보를 기재하는 것으로 다음과 같다.

index.jsp

위 파일은 다들 알다 시피 html, jsp 문법을 쓸수 있는 파일이다. 그냥 OK 글자 하나만으로도 된다.

web.xml

이 파일은 웹애플리케이션 동작에 대해 설정하는 파일이다. 다음과 같다.

그냥 index.jsp 파일에 대해서만 설정 하면 된다.

healthcheck.war 만들기

위에서 기술한 디렉토리에서 다음과 같이 입력해 war 파일을 만든다.

이렇게 하면 war 파일이 나온다.

그리고 이것을 WAS 서버에 배포하고 브라우저에서 ‘http://server:8080/healthcheck/index.jsp’ 를 호출하면 OK 가 나온다.

AWS ELB 에서 HealthCheck 설정에서 port 는 8080, URL 은 /healthcheck/index.jsp 를 기재하면 WAS 에 대한 헬스체크를 HTTP를 통해서 할 수 있게 된다.

 

 

 

 

 

 

Java 8 람다 표현식

이 글은 다음의 Youtube 강의 내용을 요약 정리한 것입니다.

  • Java 8 Lambda Basics – Java Brains

왜 람다(Lambda) 인가?

  • 함수형 프로그램이 가능하다.
  • 읽기 쉽고 간결한 코드
  • API 나 라이브러리 사용이 좀 더 쉽다.
  • 패러럴 프로그래밍이 가능하다.

람다는 함수 자체를 값으롤 할당할 수 있는 Inline 함수처럼 표현된다.

 

람다 표현식(Lambda Expressions)

자바에서 메소드로 불리우는 함수 표현식은 대략 다음과 같은 형식을 갖는다.

Inline Values

위 예제는 Inline Values 가 무엇인지 보여준다. 별다른 객체, 메소드의 도움이 바로 할당하는 형식이 바로 Inline Values 라고 보면 된다.

그렇다면 코드 블럭(Code Block) 자체를 인라인으로 할당 할 수 있지 않을까? 다음과 같이 말이다.

실제로 JavaScript 에서는 Inline 함수라고 해서 존재한다. 다음과 같은 형식을 갖는다.

Java 8 에서의 람다 표현식은 JavaScript 에서의 인라인 표기와 유사하다.

HelloWorld 람다

HelloWorld 를 통해서 람다 표현식을 익혀보자.

전형적인 HelloWorld 코드다. 이것을 람다 표현식으로 어떻게 바꿀까? 먼저 메소드 자체를 Inline Value 할당하듯이 가상의 변수에 할당해보자. 다음과 같이.

public 은 접근제한자라고 해서 protected, private 등이 있다. 변수에 할당하는 행위에서 있어서 이러한 접근제한자는 의미가 없다. OOP 에서는 객체의 변수를 직접 받는것이 아니라 메소드를 통해서 할당 받는데, 람다 표현식에서는 Inline Value 로 직접 할당하는 방식이기 때문에 무의미하다. 지우자!

코드를 다시보면 perform  이라는 함수 이름이 존재한다. 하지만 코드 블럭자체를 왼쪽 변수에 할당하고 그러한 코드 블럭은 왼쪽 aBlockOfCode 를 호출함으로써 동작하게 될터이다. 따라서 perform 이라는 함수 자체를 지칭하는 이름은 불 필요하다. 이는 앞서본 JavaScript 의 인라인함수 표현식에서처럼 할당되는 함수의 이름이 없는것과 같다. 지우자!

void 는 리턴타입을 말한다. 아무런 리턴도 없다는 의미이기도 하다. Java 8 컴파일러는 똑똑하다. 람다 표현식에서 리턴타입을 명시하지 않더라도 컴파일러가 알아서 해준다. 지우자!

다 됐다. Java 8 에서 람다 표현식에서는 ->  를 이용한다. 다음이 Java 8의 람다 표현식의 완성이다.

이게 정상적인 코드라구? 그렇다. Java 8 에 도입된 람다표현식이다. 정확하게 잘 동작한다. 위를 좀 더 간결하게 바꿔 쓸수도 있다.

 

람다(Lambda) 예제.

다음을 람다 표현식으로 바꿔보자.

Inline 변수 할당이기 때문에 객체 접근제한자는 필요가 없다. public 삭제..

Inline 변수 할당이기 때문에 double 이라는 함수자체이 이름도 필요가 없다. double 삭제.. 그러면 다음과 같은 형태만 남는다.

자바 컴파일러는 매우 똑똑하다. 리턴타입을 추론해 맞춰준다. 먼저 인자 타입이 int 형이라 결과도 나름대로 int 형일것으로 추정하기도 하고 리턴 되는 계산을 하면서 리턴타입을 추론하기도한다. 별도로 리턴타입을 정의해줄 필요가 없다. int 리턴타입 삭제…

그렇게 하고 나면 다음과 같이 람다 표현식을 쓸수 있게 된다.

람다 표현식이다. 하지만 이를 좀 더 줄이면 다음과 같이 쓸 수 있다.

한줄로 다 작성할 수가 있다면 {} 블럭을 사용할 필요가 없고 {} 없는 경우에 return 을 쓰지 않아도 된다.

모든 람다가 {} 이 필요 없는 것은 아니다. 다음과 같이 블럭내에 로직이 들어갈 경우에 {} 블럭과 return 이 필요하다.

문자열 길이를 알아내고자 한다면 어떻게 람다 표현식을 쓸 수 있나? 다음과 같다.

물론, 앞에서 처럼 뭔가 로직을 넣어야 한다면 {} 감싸고 return 을 해주면 된다.

Mac 에서 JAVA_HOME 찾기

참조: http://stackoverflow.com/questions/6588390/where-is-java-home-on-osx-sierra-10-12-el-captain-10-11-yosemite-10-10

Mac 에는 여러버전의 Java 가 설치되어 있습니다. 그런데, 가끔씩 JAVA_HOME 이 어디인지를 알고 싶을때가 있습니다. 그럴때 다음과 같이 하면 알수 있습니다.

 

 

Java 설치

이 글은 Java 를 리눅스에 설치하는 법을 다룹니다.  Java 는 JDK, JRE가 존재하는데 WAS 서버 운영을 위해서는 JDK를 설치하는게 여러모로 좋습니다.

다운로드

다운로드는 Oracle 홈페이지의 Java 페이지에서 받을 수 있습니다. 보시면 다양한 패키지를 제공하는데, 저는 64bit 리눅스 tar.gz 파일을 다운로드 받았습니다.

설치

tar.gz 파일을 다운로드 받았다면 설치는 압축을 해제하는 것으로 사실상 끝이 납니다.

설정하기

자바 설치가 끝났다면 이를 시스템이 인식할 수 있도록 설정해줍니다. 설정은 자바 홈 디렉토리, 패스, 클래스패스등을 입니다.

이를 매번 입력하기 보다는 /etc/profile 맨 아래에 적어주면 부팅할때마다 자동적으로 시스템 전체에 적용 됩니다.

 

Java BookMark

윈도우용 JDK Portable 설치.

윈도우용 JDK를 보면 Portable 설치가 없다. 설치를 할려면 Windows Installer  를 이용하는 방법 밖에 없다. 문제는 두개의 버전, 1.7과 1.8 버전의 JDK 를 설치할 수가 없을 수도 있다. 최신판을 설치된 상태에서 구 버전을 설치할려면 이미 최신버전이 설치가 되어 있어서 설치가 안될 수도 있다.

이럴때 Linux 용 처럼 압축만 해제하면 쓸수 있도록 할 수 있지 않을까? 이 글은 JDK를 압축해제하는 것만으로 설치하는 방법인 Portable 설치에 대해서 다룬다. 또한, 이글은 다음 링크의 내용을 정리한 것이다.

참고로 JDK 1.7 버전만 가지고 테스트 됐다.

준비

구 버전의 Windows Installer 를 다운받는다. 보통은 .exe 확장자로 끝나는 파일이다. 또 다른 프로그램이 필요한데 .exe 를 압축해제할 수 있는 압축/해제 소프트웨어다. 많은 압축/해제 소프트웨어가 있지만 7-zip 을 이용했다.

압축해제

jdk 압축 해제
위 그림과 같이 7-zip 을 설치한 후 마우스 오른쪽 버튼을 클릭하면 .exe 파일을 압축해제할 수 있다.

압축을 해제하면 jdk-7u80-windows-x64 디렉토리가 생성되고 그 안에 ‘tools.zip’ 압축파일이 보인다. 그럼 이 tools.zip 도 압축을 해제한다.

pack 파일을 jar 파일로 변환하기

tools.zip 파일을 보면 pack 파일들이 보인다. windows installer 의 패키징 파일이다. 이것을 unpack 해서 jar 파일로 만들어주는게 핵심이 된다.

cmd 창에서 작업을 해야해서 cmd 창을 띄운다. 그리고 방금 압축해제한 디렉토리인 tools 로 이동한다.

cmd 창에서 tools 로 이동
cmd 창에서 tools 로 이동

그리고 다음과 같이 입력한다.

위와같이 하면 pack 파일이 전부 jar 파일로 변환된다.

이제 tools 디렉토리를 ‘JDK1.7’ 로 이름을 바꾸고 C:\ 로 이동시키면 Portable 하게 설치가 완료된다.

GC 알고리즘

reference counting algorithm

count를 관리하여 reference count가 0이되면 그때그때 garbage collection을 수행하는것이다.object에 reference 가되면 reference count는 1이 증가하고 reference가 사라지면 1이 감소하는 식으로 동작한다. 그런데 이 reference 관계가 간접적이라 하더라도 참조하고 있는 모든 object에 대해 연쇄적으로 reference count가 변경된다 이reference count가 0 이될때마다 garbage collection이 발생하기 때문에 자연스럽게 Pause Time이 분산되어 실시간 작업에도 거의 영향을 주지 않는 장점이 있다. 그러나 reference의 변경이나 garbage collection의 결과에 따라 각 object마다 reference count를 변경해 주어야하기 때문에 이에 대한 관리 비용이 상당하다 또한 Garbage collecition이 연쇄적으로 일어 날수 있다는 것도 문제가 될 수 있다. 하지만 무엇보다 이 reference counting algorithm 문제는 memory leak의 가능성이 농후하다는데 있다 reference count가 0이 되어야 garbage collection이 될것인데 순환 참조의 구조에서는 regerence count가 0이 될 가능성이 희박하다 그렇기 때문에 garbage 가 되어도 heap 에서 사라지지 않게 되어 memory leak 을 유발할 가능성이 커지게 된다

mark-and-sweep algorithm

reference에 따라 object마다 count를 하는 방식대신, root set에서 시작하는 reference의 관계를 추적하는 방식을 사용한다. 이러한 방식은 garbage를 detection하는데 있어 상당히 효과적이기 때문에 이후의 garbage collection에서 detection은 대부분 이 algorithm을 사용하고 있다.

mark-and-sweep algorithm은 mark phase와 sweep phase로 나뉘어 진다. mark phase는 gabage object를 구별핸재는 단계로 root set 에서 reference 관계가 있는 object에 marking하는 방식으로 수행된다.marking 을 위해서는 여러가지 방법이 있는데 주로 object header에 flag 나 별도의 btimap table등을 사용한다

이 mark-and-sweep algorithm은 reference관계까 정확하게 파악될 뿐만 아니라 reference의 관계의 변경 시에 부가적인 작업을 하지 않기 때문에 속도가 향상된다는 장점이 있다. 그러나 garbage collection 과정 중에는 heap의 사용이 제한된다. 그것은 작업의 정확성과 meomry corruption을 방지 하기 위함인데 이 경우 프로그램이 잠깐 멈추는 현상이 발생한다 또하나의 문제는 바로 fragementation이 발생 할수 있다는 것이다.

mark-and-compaction algorithm

make-and-sweep algorithm의 fragmentation이라는 약점을 국복하고자 sweep 대신 compaction을 포함한 것이다.

이 algorithm은 mark phase와 compaction phase로 구성되어 있다. compaction이란 작업은 말 그대로 live object를 연속된 메모리 공간에 차곡차곡 적재하는 것을 의미하며 보통 하위 address로 compaction을 수행한다 compaction에는 여러가지 방식이 있는데 arbitrary 방식, linear방식, sliding 방식 등이 있다. 이중 arbitrary방식은 순서가 보장되지 않는 방식이다. linear방식은 reference의 순서대로 정렬된 compaction이다 그리고 sliding 방식은 할당된 순서대로 정렬되는 방식이다.

compaction을 원활하게 하기 위해 handle과 같은 자료구조를 사용할 수도 있다. handle에는 객체의 논리적인 주소와 실제 주소가 들어가 있다. mark phase에서는 live object의 handel에 marking한다. compaction phase에서는 일단 marking 된 정보를 바탕으로 garbage object를 sweep 한 후 heap의 한 쪽 방향으로 live object를 이동시킨다. 이동하는 방법은 sliding compaction의 방법을 사용한다. 그 이후 이동한 새로운 주소로 모든 reference를 변경하는 작업을 수행한다

fragmentation의 방지에 초점이 맞추어져 있기 때문에 메모리 공간의 효율성이 가장 큰 장점이다.그러나 compaction 작업 이후에 모든 reference를 업데이트 하는 작업은 경우에 따라서 모든 object를 access하는등의 부가적인 overhead가 수반 될 수도 있다. 또한 mark phase와 compaction phase는 모두 suspend 현상이 발생한다는 단점이 있다

copying algorithm

heap 을 active영역과 inactive 영역으로 나누어서 사요한느 특징을 가지고 있다. 이중 active영역에만 object를 할당 받을 수 있고 active영역이 꽉 차게 되어 더이상 allocation이 불가능하게 되면 garbage collection이 수행된다.

garbage collection이 수행되면 모든 프로그램은 일단 suspend 상태가 된다. 그리고 live object를 inactive영역으로 copy하는 작업을 수행한다. object를 copy할때 각각의 reference 정보도 같이 변경된다.

이렇게 작업이 끝나면 active영역에는 garbage object만 남아 있게 되고 inactive 영역에는 live object만이 남아 있게 된더. 그런데 inactive영역에 object를 copy 할 때는 한쪽 방향에서부터 차곡차곡 적재를 하기 때문에 마치 compaction을 수행한 것처럼 정렬이 된 상태가 된다 이렇게 garbage collection이 완료되는 시점에서 active 영역은 모두 freememory가 되고 active 영역과 inactive 영역은 서로 바뀌게 된다. 이를 scavenge라고 한다.

fragmantation의 방지에는 효과적이기는 하지만 전첼 heap의 절반 정도를 사용하지 못한다는 단점이 존재한다. 또한 suspend현상과 copy에 대한 overhead는 필요악이라 할 수 있을 것이다.

generational algorithm

copy algorithm의 연장선상에 있다. heap을 active, inactive로 나누는 것이 아니라 age 별로 몇개의 sub heap으로 나눈다. object는 youngest generation sub heap 에 할당되고 그 곳에서 성숙하게 되면 그 다음 age에 해당하는 sub heap으로 올라가 결국 oldest generation sub heap 까지 promotion하는 방식으로 동작한. age가 임계값을 넘엇 다른 generation으로 copy되는 것을 promotino이라고 한다.

무엇보다 이 algorithm의 장점은 각 sub heap에서 각각 적절한 algorithm을 적용 할수 있다는 것이다 이러한 장점으로 인해 hosspotjvm이나 ibm jvm에서도 generational algorithm을 사용하고 있다

train algorithm

Heap을 작은 Memory Block으로 나누어 Single Block 단위로, Mar Phase와 Copy Phase로 구성된 Garbage Collection을 수행한다.이러한 특징때문에 이 algorithm은 incremental algorithm이라고도 한다.

garbage collection을 수행하는 단위가 single block 인 만큼 전체 heap의 suspend가 아닌 collection 중인 memtory block만 suspend가 발생한다 다시 말해 suspend를 분산시켜 전체적인 pause time을 줄이자는 아이디어인 것이다.

heap을 tran으로 구성한다 이 train은 car라고 불리는 fixed size의 memory block을 묶어 놓은 체인이다. train은 필요에 따라 car를 추가 할수도 있고 하나의 train이 추가 될 수도 있다. 그리고 각 memory block은 car외부에서의 참조를 기억하는 remember set이라는 장치가 있다. 이러한 구조 때문에 train algorithm이라는 명칭을 사용하게 되었다.

remember set은 train algorithme이 single block 단위로 garbage collection을 한다는 의미에서 상당히 중요하다 copy나 compaction을 통해 objectr가 이동을 하게 되면 당연히 그 주소가 변경될 것이고 이를 참조하는 object들도 따라서 reference가 변겨이 되어야한다. 그런데 obejct가 이동을 하게 되면 당연히 그 주소가 변경될 것이고 이를 참조하는 object들도 따라서 reference가 변경이 되어야 한다. 그런데 object는 자신이 참조하는 refence는 가지고 있지만, 누가 나를 참조하고 있는지에 대한 정보는 가지고 있지 못하다. 그렇기 때문에 이동한 object를 누가 참조하고 있는지를 알기 위해서는 , 최악의 경우 모든 root set과 object의 reference를 모두찾아 다녀야 하는 경우가 발생한다. 이경우 suspend의 분산 효과는 현저히 떨어진다.

remember set은 이러한 일을 방지하는 효과가 있다. remember set을 구성하기 위해서는 write barrier라는 장치를 동반하게 된다. wite barrierㅇ는 간단한 코드로 되어 있는 instruction의 set, 즉 작은 이벤트 프로그램 또는 트리거 정도로 이해할 수 있다. 보통 write barrier는 reference 관계를 맺을때 대상 object가 같은 car에 있지 않을 경우 대상 object의 car에 있는 remember set에 기록하는 식으로 구성되어 있다

adaptive algorithm

지금까지 설명한 것과는 달리 특정 collection방법을 지칭하는 것은 아니다. heap의 현재 상황을 모니터링하여 적절한 algorithm을 선택 적용하는 것 또는 heap sizing을 자동화하는 일련의 방법을 의미한다. 이것은 hotspot jvm의 ergonomics 기능 또는 adaptive optino이나 ibm jvm의 tilting 기능 등으로 구현이 되고 있다.