본문 바로가기
프로그램 개발(분석, 설계, 코딩, 배포)/2. 개발

개발_java_java6 java7 문제

by 3604 2022. 11. 6.
728x90

개요

kth 내부 서비스 또는 kt 용역 서비스 상당수는 호환성이라는 명목 하에 java6 / java7 개발/유지보수하는 프로젝트들이 많이 있습니다.

물론 java6 / java7 개발한다고 돌던 서비스가 당장 멈추거나 하는 일은 없을겁니다만

서비스 품질은 다음과 같은 측면에서 경쟁사에 뒤쳐진다고 보시면 됩니다.

1) 보안

2) 가용성

3) 호환성

4) 기술 역량

 

보안

oracle java6 End of Public Update 2013 2, java7 2015 4월에 종료되었습니다.

무슨 말인고 하면, 누군가가 java 새로운 보안 결함을 발견한다면 java6 / java7 개발된 서비스는 더이상 보안 업데이트가 없다는 뜻입니다.

다음 사이트(oracle jre 링크) 참고하시면, 지금까지 알려진 보안 결함 리스트를 보실 있는데요.

java6 대략 200 , java7 대략 100 정도의 보안 결함 업데이트가 없었습니다.

물론 네트워크 방화벽이라던지 정기 OS 패치 등으로 이중 삼중 보안 장치를 마련해 두고 있지만

때때로 이러한 모든 보안 장치를 무력화할 만한 대형 결함이 발견되기도 하는데, 그럴 동작하는 서비스가 java6 / java7 기반이라면 대책이 없습니다.

 

가용성

Interned String 문제

java6 쓰면서 서비스에 특별한 장애 요소도 없는데 이상하게 보름에서 한달 정도 지나면 서비스가 내려가는 경험이 있으셨다면 십중팔구는 Interned String 문제입니다.

java6 java7/8 String pool 저장소가 근본적으로 다릅니다.

java6 이하 버전의 경우 신규 생성된 String PermGen 위치하며, 동일한 String 경우 pooling 합니다.

 

PermGen 사이즈는 고정이므로(java8 다릅니다만),

1) 100bytes 사이즈의 서로 다른 값을 가진 String(e.g. 임시 발급 key, UUID 등등등)

2) 100Mbytes 사이즈 PermGen

채울 있는 최대값은 100 * 1000 * 1000 = 100M 이므로

최대 100 개의 String 이상 String 신규로 생성되면 PermGen 영역이 가득차게 되고, 아래와 같은 익셉션과 함께 프로그램이 제대로 동작하지 않을겁니다.

exception

java.lang.OutOfMemoryError: PermGen space

 

java7부터는 String.intern() 메소드를 명시적으로 호출하지 않는 , PermGen 영역에 String Poolling 하지 않습니다.

단지 jvm 버전을 올리는 만으로도 가용성 장애 요소를 가지 줄일 있습니다.

 

Fixed PermGen size 문제

허나, java7 이하 버전에서 여전히 PermGen size 고정이라는 문제가 존재합니다.

대개의 경우 String PermGen space 잡아먹는 주된 요인이겠지만,

본래 PermGen 주된 목적은 어플리케이션에서 사용되는(=load) class 정보의 저장입니다.

java7에서 PermGen 사이즈를 적당히 크게 잡아줄 경우, PermGen 고갈되는 경우는 왠만해선 발생하지 않겠습니다만

다음과 같은 시나리오에서는 PermGen 고갈됩니다.

1) classloader 동적으로 신규 class 지속적으로 load

2) 프로그램 사이즈가 정말 커서 많은 class 필요

PermGen 사이즈는 고정이라는 원죄가 있기 때문에 jvm 옵션으로 PermGen 사이즈를 조정하더라도 항상 문제가 발생할 여지가 있습니다.

java8 에서는 PermGen 사라진 대신 해당 역할을 metaspace 대체합니다.

차이점은 다음과 같습니다.

1) metaspace 메모리 영역은 native 입니다.

2) memory 부족하면 동적으로 할당 가능합니다.

 

cf) PermGen?

2015년도 신입사원 교육자료  2일차, dependency hell 작성할 그려둔 native application memory 모델입니다.

물론 java 디테일에는 차이가 있지만, Heap / Stack / Data / Code 섹션에 대한 포괄적인 개념은

java native 혹은 이후 여러분들이 접하게 어떤 언어라도 대동소이합니다. 하나만 제대로 알고 있으면 되겠죠?

 SHAPE  \* MERGEFORMAT

메모리 모델은 내가 프로그램이 실제로 어떻게 작동하는지 알고 싶은 개발자라면 반드시 대가리헤또에 필수 탑재되어 있어야 합니다.

메모리 모델

stack : 프로그램의 흐름(=function call), local 변수 등을 저장

heap : 프로그램 내에서 동적으로 할당한 데이더를 저장

data : 전역변수를 저장

code : 프로그램 메타정보(=function meta) 등을 저장

메모리 영역별로 역할이 주어져 있지만, 가장 중요한 핵심은

1) 어플리케이션 시작 전에 사이즈를 결정할 있는 영역과(code / data)

2) 어플리케이션 실행 도중에 사이즈가 변경되는 영역(stack / heap)

분리되어 있다는 점입니다.

 

디테일은 다르지만 자바 메모리모델도 어플리케이션 시작 전에 사이즈를 결정할 있는 영역과 그렇지 않은 영역으로 구분됩니다.

다만, PermGen 영역의 정체성이 모호한데요.

본래 의도대로라면 PermGen 영역은 런타임에 증가되어선 안되는 영역입니다만 가지 경우에 예외를 두었고

예외 때문에 자바 어플리케이션은 지금까지 고통받아 왔습니다.

 

java memory model

아래 그림은 어떤 존잘님께서 그린 java 메모리 모델입니다. (출처http://javarevisited.blogspot.com/2011/04/garbage-collection-in-java.html)

1) java7 이하 메모리 모델

2) java8 메모리 모델

Compressed Ordinary Object Pointer default enabled

jvm에는 Ordinary Object Pointer, 줄여서 OOP(객체지향 프로그래밍과 혼동 금지!, 보통 hotspot oop 라고 부릅니다.) 대한 압축을 enable / disable 하는 옵션이 있습니다.

hotspot oop 기회가 된다면 나중에 따로 다루겠지만, 간단히 요약하면

데이터의 주소 정보를 효율적으로 쓰기 위한 꼼수

라고 보시면 됩니다.

compressed oop 옵션은 java7부터 default enabled 입니다.

만일 64bit 플랫폼 환경에서 java6 쓰신다면 어플리케이션 실행 옵션을 enable 하여야 메모리를 효율적으로 있습니다.

 

호환성

신규 버전의 java 에는 보안 / 기능 / 성능 / 정책 위배 여러가지 사유로 과거 버전중 deprecated 되는 API들이 발생합니다.

java6 또는 java7에서 java8 올리지 못하는 여러 가지 이유중에는 deprecated API 대한 호환성 문제가 비중이 높은 편인데요.

당장 deprecated API 수정할 여력 없이 운영만 하는 서비스는 현실적으로 java 버전을 높이기 어려운 것이 사실입니다.

허나 신규 프로젝트에서 deprecated API 사용하거나, 해당 API 사용한 library 쓰는 일은 없어야 합니다.

이미 배포한 API 없앤다는 정말 어려운 일입니다. 그래서 보통은 왠만하면 해당 API 없애지 않고 구현을 변경하거나 다른 좋은 구현을 만들어내 해당 API 사용률을 낮추도록 유도합니다.

그럼에도 불구하고 API 없애는 결정을 했다는건 정말 API 쓰지 말아야 중대한 이유가 있기 때문에 없애는 겁니다.(쓰지 말라면 쓰지 마루요)

아래 링크는 oracle에서 제공하는 java7 / java8 deprecated api 리스트 java8 호환성 guide 문서입니다.

호환성

java7 deprecated APIs : https://docs.oracle.com/javase/7/docs/api/deprecated-list.html

java8 deprecated APIs : https://docs.oracle.com/javase/8/docs/api/deprecated-list.html

java8 호환성 가이드http://www.oracle.com/technetwork/java/javase/8-compatibility-guide-2156366.html#A999081

 

기술역량

modern language 열풍이 분지 올해로 10 지났습니다.

무수히 많은 modern language 생겨나기도 하였지만, 기존 language들이 modern language 철학을 담는 경우도 종종 있었습니다.

java 다른 언어에 비해 modern language 주요 개념, 기능 등을 담아내는 시점이 매우 늦은 편입니다.

심지어 java보다 30년은 오래된 c++ 오히려 java보다 100만배는 modern 합니다.

 

현대의 소프트웨어 개발 환경은 가지 특징이 있습니다.

1) 과거에 비해 어플리케이션의 규모 / 복잡도가 기하급수적으로 높아졌습니다.

2) 난립하는 하드웨어에 효율적으로 대응하기 위한 수단이 필요합니다.

3) 더이상 수직적인 하드웨어 성능은 높아지지 않습니다. 허나 처리해야 데이터의 양은 엄청나게 늘었습니다.

 

과거, 구조적 프로그래밍의 한계를 객체지향 프로그래밍으로 극복한 시절이 있었습니다.

현재는 객체지향 프로그래밍의 한계에 다다랐다고 보아도 과언이 아닙니다.

우리가 쓰는 대부분의 CPU 멀티코어 프로세서로 설계되었습니다.

허나 객체지향 언어로 멀티코어 성능을 온전히 내는 어플리케이션을 만들기는 매우 어렵습니다. 디버깅은 100만배 어렵습니다.

 

과거, 비동기 네트워킹은 시스템 프로그래머만의 전유물이던 시절이 있었습니다.

현재는 클라이언트 프로그래머도 비동기 처리의 동작 원리를 반드시 이해하여야 합니다.

비동기 처리는 반드시 OS 지원 / 프로그램 언어의 지원이 필요합니다.

 

modern language 에는 다음과 같은 가지 공통적인 특징이 있습니다.

1) 함수형 프로그래밍 패러다임 수용

2) 불필요한 코드 노가다 지양

3) 강력한 type 추론

4) lazy execution 구현하기 위한 효율적인 수단 제공

5) REPL(Read – Evelauation – Print – Loop) 또는 준하는 어플리케이션 확인 수단 제공

6) thread local stack 대한 디버깅 수단 제공

 

java8 많이 늦은 편인데 이러한 소프트웨어 개발 환경의 변화를 java6 / java7 대응한다? 쉽지 않습니다.

지금으로부터 40 , 프로그래밍 세계를 평정하던 cobol이라는 언어가 있었습니다.

당시 두터운 사용자/커뮤니티층을 형성하던 cobol 개발자들은 굳이 OOP 학습할 필요성을 느끼지 못하였습니다.

c++ 출시되고 10년이 못되어 cobol 어플리케이션은 씨가 말랐고, OOP 대세가 되었습니다.

요즘의 java 보면서 과거 cobol 역사가 자꾸 오버랩되는 것은 우연의 일치일까요?

 

개요

kth 내부 서비스 또는 kt 용역 서비스 상당수는 호환성이라는 명목 하에 java6 / java7 개발/유지보수하는 프로젝트들이 많이 있습니다.

물론 java6 / java7 개발한다고 돌던 서비스가 당장 멈추거나 하는 일은 없을겁니다만

서비스 품질은 다음과 같은 측면에서 경쟁사에 뒤쳐진다고 보시면 됩니다.

1) 보안

2) 가용성

3) 호환성

4) 기술 역량

 

보안

oracle java6 End of Public Update 2013 2, java7 2015 4월에 종료되었습니다.

무슨 말인고 하면, 누군가가 java 새로운 보안 결함을 발견한다면 java6 / java7 개발된 서비스는 더이상 보안 업데이트가 없다는 뜻입니다.

다음 사이트(oracle jre 링크) 참고하시면, 지금까지 알려진 보안 결함 리스트를 보실 있는데요.

java6 대략 200 , java7 대략 100 정도의 보안 결함 업데이트가 없었습니다.

물론 네트워크 방화벽이라던지 정기 OS 패치 등으로 이중 삼중 보안 장치를 마련해 두고 있지만

때때로 이러한 모든 보안 장치를 무력화할 만한 대형 결함이 발견되기도 하는데, 그럴 동작하는 서비스가 java6 / java7 기반이라면 대책이 없습니다.

 

가용성

Interned String 문제

java6 쓰면서 서비스에 특별한 장애 요소도 없는데 이상하게 보름에서 한달 정도 지나면 서비스가 내려가는 경험이 있으셨다면 십중팔구는 Interned String 문제입니다.

java6 java7/8 String pool 저장소가 근본적으로 다릅니다.

java6 이하 버전의 경우 신규 생성된 String PermGen 위치하며, 동일한 String 경우 pooling 합니다.

 

PermGen 사이즈는 고정이므로(java8 다릅니다만),

1) 100bytes 사이즈의 서로 다른 값을 가진 String(e.g. 임시 발급 key, UUID 등등등)

2) 100Mbytes 사이즈 PermGen

채울 있는 최대값은 100 * 1000 * 1000 = 100M 이므로

최대 100 개의 String 이상 String 신규로 생성되면 PermGen 영역이 가득차게 되고, 아래와 같은 익셉션과 함께 프로그램이 제대로 동작하지 않을겁니다.

exception

java.lang.OutOfMemoryError: PermGen space

 

java7부터는 String.intern() 메소드를 명시적으로 호출하지 않는 , PermGen 영역에 String Poolling 하지 않습니다.

단지 jvm 버전을 올리는 만으로도 가용성 장애 요소를 가지 줄일 있습니다.

 

Fixed PermGen size 문제

허나, java7 이하 버전에서 여전히 PermGen size 고정이라는 문제가 존재합니다.

대개의 경우 String PermGen space 잡아먹는 주된 요인이겠지만,

본래 PermGen 주된 목적은 어플리케이션에서 사용되는(=load) class 정보의 저장입니다.

java7에서 PermGen 사이즈를 적당히 크게 잡아줄 경우, PermGen 고갈되는 경우는 왠만해선 발생하지 않겠습니다만

다음과 같은 시나리오에서는 PermGen 고갈됩니다.

1) classloader 동적으로 신규 class 지속적으로 load

2) 프로그램 사이즈가 정말 커서 많은 class 필요

PermGen 사이즈는 고정이라는 원죄가 있기 때문에 jvm 옵션으로 PermGen 사이즈를 조정하더라도 항상 문제가 발생할 여지가 있습니다.

java8 에서는 PermGen 사라진 대신 해당 역할을 metaspace 대체합니다.

차이점은 다음과 같습니다.

1) metaspace 메모리 영역은 native 입니다.

2) memory 부족하면 동적으로 할당 가능합니다.

 

cf) PermGen?

2015년도 신입사원 교육자료  2일차, dependency hell 작성할 그려둔 native application memory 모델입니다.

물론 java 디테일에는 차이가 있지만, Heap / Stack / Data / Code 섹션에 대한 포괄적인 개념은

java native 혹은 이후 여러분들이 접하게 어떤 언어라도 대동소이합니다. 하나만 제대로 알고 있으면 되겠죠?

 SHAPE  \* MERGEFORMAT

메모리 모델은 내가 프로그램이 실제로 어떻게 작동하는지 알고 싶은 개발자라면 반드시 대가리헤또에 필수 탑재되어 있어야 합니다.

메모리 모델

stack : 프로그램의 흐름(=function call), local 변수 등을 저장

heap : 프로그램 내에서 동적으로 할당한 데이더를 저장

data : 전역변수를 저장

code : 프로그램 메타정보(=function meta) 등을 저장

메모리 영역별로 역할이 주어져 있지만, 가장 중요한 핵심은

1) 어플리케이션 시작 전에 사이즈를 결정할 있는 영역과(code / data)

2) 어플리케이션 실행 도중에 사이즈가 변경되는 영역(stack / heap)

분리되어 있다는 점입니다.

 

디테일은 다르지만 자바 메모리모델도 어플리케이션 시작 전에 사이즈를 결정할 있는 영역과 그렇지 않은 영역으로 구분됩니다.

다만, PermGen 영역의 정체성이 모호한데요.

본래 의도대로라면 PermGen 영역은 런타임에 증가되어선 안되는 영역입니다만 가지 경우에 예외를 두었고

예외 때문에 자바 어플리케이션은 지금까지 고통받아 왔습니다.

 

java memory model

아래 그림은 어떤 존잘님께서 그린 java 메모리 모델입니다. (출처http://javarevisited.blogspot.com/2011/04/garbage-collection-in-java.html)

1) java7 이하 메모리 모델

2) java8 메모리 모델

 

Compressed Ordinary Object Pointer default enabled

jvm에는 Ordinary Object Pointer, 줄여서 OOP(객체지향 프로그래밍과 혼동 금지!, 보통 hotspot oop 라고 부릅니다.) 대한 압축을 enable / disable 하는 옵션이 있습니다.

hotspot oop 기회가 된다면 나중에 따로 다루겠지만, 간단히 요약하면

데이터의 주소 정보를 효율적으로 쓰기 위한 꼼수

라고 보시면 됩니다.

compressed oop 옵션은 java7부터 default enabled 입니다.

만일 64bit 플랫폼 환경에서 java6 쓰신다면 어플리케이션 실행 옵션을 enable 하여야 메모리를 효율적으로 있습니다.

 

호환성

신규 버전의 java 에는 보안 / 기능 / 성능 / 정책 위배 여러가지 사유로 과거 버전중 deprecated 되는 API들이 발생합니다.

java6 또는 java7에서 java8 올리지 못하는 여러 가지 이유중에는 deprecated API 대한 호환성 문제가 비중이 높은 편인데요.

당장 deprecated API 수정할 여력 없이 운영만 하는 서비스는 현실적으로 java 버전을 높이기 어려운 것이 사실입니다.

허나 신규 프로젝트에서 deprecated API 사용하거나, 해당 API 사용한 library 쓰는 일은 없어야 합니다.

이미 배포한 API 없앤다는 정말 어려운 일입니다. 그래서 보통은 왠만하면 해당 API 없애지 않고 구현을 변경하거나 다른 좋은 구현을 만들어내 해당 API 사용률을 낮추도록 유도합니다.

그럼에도 불구하고 API 없애는 결정을 했다는건 정말 API 쓰지 말아야 중대한 이유가 있기 때문에 없애는 겁니다.(쓰지 말라면 쓰지 마루요)

아래 링크는 oracle에서 제공하는 java7 / java8 deprecated api 리스트 java8 호환성 guide 문서입니다.

호환성

java7 deprecated APIs : https://docs.oracle.com/javase/7/docs/api/deprecated-list.html

java8 deprecated APIs : https://docs.oracle.com/javase/8/docs/api/deprecated-list.html

java8 호환성 가이드http://www.oracle.com/technetwork/java/javase/8-compatibility-guide-2156366.html#A999081

 

기술역량

modern language 열풍이 분지 올해로 10 지났습니다.

무수히 많은 modern language 생겨나기도 하였지만, 기존 language들이 modern language 철학을 담는 경우도 종종 있었습니다.

java 다른 언어에 비해 modern language 주요 개념, 기능 등을 담아내는 시점이 매우 늦은 편입니다.

심지어 java보다 30년은 오래된 c++ 오히려 java보다 100만배는 modern 합니다.

 

현대의 소프트웨어 개발 환경은 가지 특징이 있습니다.

1) 과거에 비해 어플리케이션의 규모 / 복잡도가 기하급수적으로 높아졌습니다.

2) 난립하는 하드웨어에 효율적으로 대응하기 위한 수단이 필요합니다.

3) 더이상 수직적인 하드웨어 성능은 높아지지 않습니다. 허나 처리해야 데이터의 양은 엄청나게 늘었습니다.

 

과거, 구조적 프로그래밍의 한계를 객체지향 프로그래밍으로 극복한 시절이 있었습니다.

현재는 객체지향 프로그래밍의 한계에 다다랐다고 보아도 과언이 아닙니다.

우리가 쓰는 대부분의 CPU 멀티코어 프로세서로 설계되었습니다.

허나 객체지향 언어로 멀티코어 성능을 온전히 내는 어플리케이션을 만들기는 매우 어렵습니다. 디버깅은 100만배 어렵습니다.

 

과거, 비동기 네트워킹은 시스템 프로그래머만의 전유물이던 시절이 있었습니다.

현재는 클라이언트 프로그래머도 비동기 처리의 동작 원리를 반드시 이해하여야 합니다.

비동기 처리는 반드시 OS 지원 / 프로그램 언어의 지원이 필요합니다.

 

modern language 에는 다음과 같은 가지 공통적인 특징이 있습니다.

1) 함수형 프로그래밍 패러다임 수용

2) 불필요한 코드 노가다 지양

3) 강력한 type 추론

4) lazy execution 구현하기 위한 효율적인 수단 제공

5) REPL(Read – Evelauation – Print – Loop) 또는 준하는 어플리케이션 확인 수단 제공

6) thread local stack 대한 디버깅 수단 제공

 

java8 많이 늦은 편인데 이러한 소프트웨어 개발 환경의 변화를 java6 / java7 대응한다? 쉽지 않습니다.

지금으로부터 40 , 프로그래밍 세계를 평정하던 cobol이라는 언어가 있었습니다.

당시 두터운 사용자/커뮤니티층을 형성하던 cobol 개발자들은 굳이 OOP 학습할 필요성을 느끼지 못하였습니다.

c++ 출시되고 10년이 못되어 cobol 어플리케이션은 씨가 말랐고, OOP 대세가 되었습니다.

요즘의 java 보면서 과거 cobol 역사가 자꾸 오버랩되는 것은 우연의 일치일까요?

 

 

728x90