월요일, 12월 07, 2015

소프트웨어 전문 기업에서 연구 방법

최근 신입 연구원 지망자들을 면접하면서 소프트웨어를 직업으로 삼으려는 학생들 수준이 예전보다 많이 높아졌음을 느낀다.
국민적으로 소프트웨어의 중요성에 대한 평가가 그만큼 올라갔고, 또 소프트웨어를 통한 자기 실현의 기회가 상대적으로 많아졌기 때문인 것 같다.
아래는 소프트웨어 전문 기업의 연구소를 이끌면서 느끼는 개인적 감흥이라고 할 수 있겠다.
너무 당연한 이야기일지 모르지만, 실제로는 잘 되지 않는 것들에 대한 기록이다.

연구원별 과제 선정

소프트웨어 기업의 연구소는 어느 수준 이상의 연구개발 능력이 필요한 곳이다.
연구원들은 모두 동일한 능력을 갖지 않는다. 지적 노동을 하는 연구원들은 수준이 천차만별이지만, 일단 연구원으로서 연구개발 업무를 수행하기 위해서 필요한 기본 수준은 만족해야 한다.

우수한 인재
매우 우수한 사람은 흥미를 잃지 않을 주제를 주면 알아서 잘 한다. 이런 경우에는 어떤 가치 있는 주제를 기업 차원에서 연구해야 하는지 고민하고 이를 연구원과 잘 컨센서스를 이루는 것이 중요하다. 연구 주제에 흥미를 잃거나 포커스를 놓치게 되면 동기 부여에 실패하여 퍼포먼스가 급격하게 떨어지고, 타 회사로 이직을 고민하게 되는 경우가 있다.
연구의 가치와 방향에 대해서 항상 잘 조율이 되어 있어야 하고 초기에 궤도에 오를 때까지 주제와 방향을 잘 공유해야 한다.

평범한 인재
반면 상대적으로 평범한 연구원들도 많이 있다.
보통의 연구원들은 주제를 정해준다고 해서 충분히 방향을 잘 정하지 못하는 경우가 많다.
연구원의 능력에 따라 주제와 범위, 그리고 해결에 대한 방향까지 제시해줘야 하는 경우가 종종 생긴다. 이런 연구원들은 코칭이 늘 필요하고, 수준에 맞게 연구 수준과 범위를 좁혀줄 필요가 있다.
잠깐만 방향을 잃어도 퍼포먼스가 급격하게 떨어지는 경우가 많으므로 관리는 시간적으로 더 자주 일어나야 한다.

매니저와 연구원
연구 과제는 연구소에서는 누구나 진행할 필요가 있다.
단순 관리자가 필요하지 않은 연구소의 특성 상, 상위 관리자도 역시 기본적으로는 연구를 진행하고 또 리딩해야 한다.
매니저/디렉터는 전략적 판단이 필요하고 범위가 넓은 경우에 대해서는 직접적인 연구를 진행하거나 집중적으로 리딩하는 게 좋다. 물론 매니저가 개발까지 직접 담당할 필요는 없다.
개별 연구원은 상대적으로 범위가 좁고, 깊이가 필요한 경우에 대해 직접적인 연구 개발을 진행하는 것이 일반적으로 효율적이다.
(천재 연구원이라면 범위나 깊이 모두 고려 사항이 아니다. 가장 복잡도가 높은 핵심 연구를 맡겨야 한다.)

연구 과제를 공유하는 내부 세미나 준비

연구소의 소프트웨어 연구 개발은 주로 특정 영역을 이해하고 이를 아키텍처 측면에서 검토하고 설계를 진행하는 영역이 주가 된다.
시스템 소프트웨어는 특성 상 단순 개발보다는 늘 설계가 선행되어야 하는 복잡성 높은 소프트웨어이기 때문에 개발을 위한 개발은 지양하고 전체를 이해하는 설계를 전제로 개발하는 게 일반적이다.

설계나 특정 영역의 이해와 같은 연구를 진행하기 위해 필요한 단계들은 어떤 경우든 반드시 거칠 필요가 있는데 개별 연구원들은 다음 단계를 통해 검증된 결과를 연구소의 여러 단위(팀-실-연구소 등)에서 공유하도록 한다.

기술 세미나를 준비할 때에는 다음의 단계가 필요하다.

1. Analysis Phase

첫번째 단계는 해당하는 도메인 지식들의 분석과 관련 지식들의 탐색이다.

연구소에 있으면서 기술 회의를 매우 많이 진행하는데 신입 연구원들에 비해 타 기업이나 국책 연구소에 있다가 경력으로 들어온 연구원들이 잘 적응하지 못하는 경우가 있다.
대부분 분석 능력에서 차이가 많이 난다.
이것은 우리나라 소프트웨어 기업 문화의 문제라고도 볼 수 있는데 소프트웨어 개발자들이 설계 수준이나 이해의 수준이 별로 높지 않고, 스펙이나, buzzword나 블로그, 컨설팅 회사의 주장을 그냥 암기하는 경향이 강하기 때문이다.
비판적 분석을 하지 못하고 좋은 말들만 옮기기 때문에 이해의 수준이 떨어지고, 또 대부분 영어로 된 글들을 그저 암기하기 때문에 실제 그 영어 단어들이 무슨 뜻인지 모르고 고유명사처럼 옮기는 경우가 많이 있다.
단순한 외부 스펙이나 주장의 요약에 그치는 경우가 많아 그 주장의 배경이나 메커니즘을 설명하지 못해 이해조차 이루지 못하는 경우가 종종 있다.
또, 이해의 수준이 피상적이기 때문에 여러 사람들이 토론을 통해 인식의 오류를 지적하고 더 나은 대안을 찾는 문화에도 잘 적응을 하지 못한다.
오히려 신입 연구원들은 이러한 나쁜 습성이 없어서 적응을 빨리 하는 경향이 있다.

Analysis Phase에서는 분석과 bottom-up의 과정이 계속 반복되어야 한다.
분석의 반복 과정에서 명심해야 할 세 가지는 다음과 같다.

  • Finding Key Problems 풀려고 하는 핵심 이슈는 무엇인가? 현재 다루는 연구 도메인의 핵심 문제를 파악해야 한다.
  • Why 왜 이렇게 했을까? 각각의 메커니즘들의 배경을 유추해야 진정한 이해가 된다.
  • Recognize Hidden Problems 각 결정들, 혹은 해법에 대한 문제점은 무엇인가? 문제가 없는 해법은 없다. 제시한 해법들에 대한 드러나지 않은 문제를 파악해야 한다.


2. Storyline Phase

두번째 단계는 스토리라인을 만들면서 생각을 정리하는 단계이다.

스토리라인을 만들면서 다시 분석과 스토리라인 보완을 반복한다.
생각을 정리하는 단계를 굳이 스토리라인이라고 표현하는 이유는 생각의 전체적인 흐름이 표현되도록 기승전결을 갖추어 정리하는 게 좋기 때문이다.

3. Deepening Phase

세번째 단계는 스토리를 심화시켜 의도했던 바가 이루어졌는지 점검하는 단계이다.
원래의 의도가 현재까지 분석 속에서 이루어졌고, 또 스토리 라인에 반영이 되었는지 체크를 한다.
이 단계에서 각 기술 요소들의 배경, 원인에 대한 부분이 제대로 파악되었는지 재점검을 한다.
빠지거나 부족한 부분에 대해서 다시 Analysis와 Storyline 보완을 반복한다.

4. Decision Phase

결론에 해당하는 부분을 의도와 시나리오에 맞게 검토한다.
실질적인 판단이 이루어지고 결론이 내려져야 한다.
물론,  결론이 완성되지 못하고 다음 연구로 이어질 부분에 대해서는 다음 연구 과제 후보로 큐잉한다.

위의 Phase들은 세미나 발표의 단계라기보다는 연구의 일반적인 판단 및 결정의 단계라고 볼 수 있을 것이다.

많은 연구원들은 1,2단계를 한번만 거치고 세미나를 하는 경향이 있다.
하지만, 의미있는 연구의 결과를 공유하기 위해서는 훨씬 더 많은 iteration이 이루어져야 한다.
storyline을 1차로 구성한 이후에도 전체적인 맥락과 개별 기술적 논리 검증 과정에서 3단계가 한 번 이상 처음부터 끝까지 검토하면서 이루어져야 하고, 마지막 결론부를 작성하기 이르러서는 다시 한 번 전체적인 논지의 문제에 대한 점검이 이루어져야 한다.
여러번의 iteration을 거치면서 사고의 흐름을 계속 유지하고 있어야 하기 때문에 연구의 성과는 집중도에 의해 많이 좌우된다. 생각이 끊어지면 좋은 결론과 더 나은 아이디어가 나올 수가 없다. 몰입(Flow)이 필요하다.

한번만에 쉽게 좋은 결론을 내릴 수 있는 경우도 없다고 할 수는 없겠지만, 그런 경우는 상대적으로 잘 알려진 기술이거나 scope이 작은 경우일 것 같다.
성급한 결론이나 단순한 지식의 전달은 좋은 연구라고 하기 어렵다.

연구소는 늘 팀 이상의 집단 공유를 거쳐서 결과물을 검증하고 평가한다.
시스템 소프트웨어 기업의 유의미한 발전은 이러한 성과들 하나하나에 기초하기 때문이다.


맺는 말
연구원들에게 늘 동기 부여를 하고 또 가치있는 성과를 만들어내도록 하는 것은 정말 어려운 일이다.
연구소는 세미나 발표를 연구원의 성과를 공유하고, 또 평가하는 목적으로도 활용하며, 또 세미나 준비 과정에서 연구원들의 지적 성장을 유도하는 코칭의 목적으로도 활용한다.

교육 효과를 나타내는 교육 피라미드를 보면 일방적으로 수업을 듣는 방식은 학생들의 교육 효과가 그다지 높지 않다.
가장 효과가 좋은 방식은 학생이 선생이 되어 직접 가르쳐보는 것이다.
세미나 발표는 학생에게 선생이 되는 계기를 만들어준다.

물론 이런 회의에 참여하는 사람들의 적극적인 문답을 통한 공유도 중요하다. 소크라테스의 문답을 통한 교수 과정처럼.
깊이 있는 기술적 창의는 문화가 뒷받침해야 함을 많은 기술 세미나와 여러 규모의 회의 속에서 수없이 되새기게 된다.

일요일, 12월 06, 2015

[Java] Java 관련한 간단한 테스트

문득 생각나서 몇 가지 간단한 Java  테스트

1. private static method의 코드 블록 크기가 작을 경우 javac는 가볍게 inline 시켜줌.
(즉, 해당 method는 바이트코드에서 사라져버리고 caller method에 inline됨.)

2. instanceof 연산자가 getClass()를 ==비교하는 것보다 훨씬 빠름.
(instanceof는 child class여부까지 체크해야 함에도 불구하고)

3. instanceof 연산을 할 때 exact class에 대해 호출하는 것이 parent class나 interface에 대해 호출하는 것보다 더 빠름. (당연!)

4. java.lang.Object의 clone() 메소드를 사용하여 객체를 shallow copy하는 것은 그다지 효율적으로 구현되지 않아서 직접 copy() 메소드를 구현하여 멤버값들을 복사해주는 것이 대부분 더 빠름.
(자바는 C의 struct처럼value object 개념이 없어 메모리 복사만으로 clone할 수 없으므로)


일요일, 8월 09, 2015

[Java] Java G1 GC의 특성에 따른 Full GC 회피 튜닝 방법

Java 6 중반부터 G1 GC가 나오면서 이 새로운 Java VM GC 정책을 두고 성능 튜닝을 어떻게 할지 고민이 많은 것 같다.

일단 생소하기 때문에 어렵다.

그런데 경험들이 조금씩 쌓이면서 문제점도 꽤 발견되는 것 같다.

먼저 G1GC를 이해하는 데 유용한 사이트이다.


JDK 7부터 기본이 된 G1(garbage first) GC는 JVM의 Heap 메모리를 1MB 정도 크기의 region들로 나눠서 region별로 generation을 지정하여 상당히 효율이 좋지만 튜닝하는 게 까다롭다.
(새로운 메모리 처리 구조에 대한 튜닝 경험도 많이 부족해서 더욱 까다롭게 느껴지는 것 같다.)

지금까지 널리 알려진 문제로는 첫째, perm generation collection을 full gc때만 하는 문제가 있다.
즉, 클래스 언로딩을 full gc때만해서 자주 재배포가 발생하는 코드가 있는 경우 문제가 될 수 있다.
앞으로는 perm generation을 완전히 없애도록 JVM의 방향을 잡고 있기 때문에 당분간 이 문제는 해결하지 않을 것으로 보인다.

둘째, G1 GC에서 거대 객체(humongous object)라고 부르는 메모리 사용량이 큰 객체들에 대한 처리는 아직 최적화되지 않았다. 보통 한 region의 50% 크기를 넘으면 거대 객체로 분류되는데 G1 GC의 한 region 크기는 보통 1MB~32MB 정도이므로 거대 객체를 많이 사용해야 한다면 다른 gc policy를 선택하는 게 맞을 것이다.

셋째, young generation 즉, eden space에 대한 gc는 매우 빠르게 처리되지만, 일단 old로 넘어간 객체들의 컬렉션은 실행이 잘 되지 않는다는 것이 경험적으로 파악되었다.

그래서 full gc를 피하기가 어렵다. (그런데 full gc 가 상대적으로는 다른 JVM에 비해 매우 빠르긴 하다.)
full gc가 시간이 짧다고 해도 성격 상 JVM의 모든 프로세싱을 중지시키는 STOP-THE-WORLD 방식이기 때문에 문제가 없는 것은 아니다.
(G1 GC에서는 young이든 old이든 copy하는 경우는 모두 STW 방식이다)

때문에 여러 가지 블로그나 기사를 통해 full gc를 회피할 수 있는 옵션을 찾아봤지만 실제로는 잘 동작하지 않았다.

그런데 Spark와 같은 대용량 메모리 처리시스템을 다루는 이들이 이 old generation region들에 대한 gc 옵션을 찾아놓았다.
다음 사이트의 기사를 읽어보자.
이들이 내세운 플래그는 바로 다음이다.

-XX:+UseG1GC -XX:+UnlockDiagnosticVMOptions -XX:+G1SummarizeConcMark -XX:InitiatingHeapOccupancyPercent=35 -XX:ConcGCThread=20
-XX:+PrintFlagsFinal -XX:+PrintReferenceGC -verbose:gc -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintAdaptiveSizePolicy
이 옵션들 중 full gc를 회피하기 위해 알아둬야 할 G1 GC의 튜닝에관련된 핵심 정보는
  1. ConcGCThread갯수를 좀더 많이 사용하도록 옵션 설정
  2. InitiatingHeapOccupancyPercent옵션을 좀더 작게 설정하는 것이다.(기본값은 45이다.) 
두번째 옵션은 언제 eden이 아닌 old heap 쪽 region들을 언제부터 mark할 것이냐를 지정하는 옵션이다.
기본값 45는 region 크기(기본값 1MB)의 45%가 차면 mark를 시작한다는 뜻.
35를 지정하면 35%만 되어도 시작한다는 뜻이다.

이외에도 다른 정보들을 참고하면 다음 GC 쓰레드 갯수 관련 옵션들도 도움이 될 수 있다.

-XX:G1ConcRefinementThreads=20
-XX:ParallelGCThreads=20
-XX:ConcGCThreads=20 (이 옵션은 위에서 이미 언급)

주의할 점은 ConcGCThread 갯수를 늘리고 InitiatingHeapOccupancyPercent 비율을 줄이면 old region에 대한 concurrent gc를 자주 실행시켜 결국 full gc 즉, single-thread에 의해 처리되는 stop-the-world의 시간을 늦출 수 있다.
하지만 old region에 대해 쓰레드간 경쟁을 발생시켜 전반적으로 성능이 불안해지게 되는 문제가 있다.

stop-the-world 시간은 0.03초 정도인데 concurrent gc는 이를 회피하기 위해 매번 수행 시마다 수 분이 걸린다면 어느 게 더 나은 튜닝일까?

이것에 대한 선택은 좀더 고민해볼 필요가 있을 것이다.
기존 HotSpot JVM에서 Concurrent-Mark-&-Swap 방식을 사용할 것인가 Performance 우선 방식을 사용할 것인가 고민했던 것과 별반 다르지 않은 고민을 G1 GC 내부적으로 하게 되는 것 같다.

예전에 올렸던 아래 글 참고

G1 GC는 테스트해본 결과 별도의 파라미터를 지정하지 않더라도 상당히 효율적으로 메모리 관리를 하는 편이다. 반대로 힘들게 파라미터 튜닝을 해도 효과가 잘 드러나지 않는 편이기도 하다. ㅠ_ㅠ;

stop the world 시간이 짧으므로 주기적으로 idle time에 강제로 full gc를 실행하는 것도 서비스 품질을 유지하기 위해 필요한 정책이 아닐까 생각해볼 수 있다.
하지만, 강제로 full gc가 실행되는 걸 보장하려면 JVMTI를 사용하는 수밖에 없다.

G1 GC는 Old Generation GC를 꼭 필요할 때에만 실행한다. 보통 New Area와 Old Area 비율이 일정 값 이하로 떨어질 때 실행하게 된다. Young GC만 하다가 Old Area가 지속적으로 증가하여 New Area가 감소되면 Old Generation GC를 통해 어느 정도 회복을 한다.
물론 이 과정에서도 충분히 회복을 하지 못하면 결국엔 Full GC를 통해 회복을 하게 된다.

이 개념들을 잘 조합해서 G1 GC 튜닝을 이루기 바란다. 보통은 튜닝할 일이 없을 정도로 잘 동작하는 G1 GC이고 Region 개념상 효과적으로 큰 메모리를 적은 pause time으로 관리할 수 있지만 Full GC는 명시적으로 실행하거나 피하는 것이 최선이라고 할 수 있다.




참고 : G1 GC에서 실행하는 세 가지 유형의 collector 
자세한 내용은 위 오라클의 G1 GC 소개 페이지를 참조하면 된다.
간략하게 설명하면 다음 세 가지로 구성된다.
먼저 G1 GC에서 JVM Heap 영역은 1MB~32MB 이내의 고정된 크기로 2000여개 영역으로 분할되어 있다. 이 고정 크기 부분 영역을 Region이라고 부른다.
각 Region은 기존 JVM heap의 영역이었던 New Area(Eden Area), Survivor Area, Old Generation Area, Permant Generation Area를 각각 담당하지만, 동적으로 역할이 변경될 수 있다.
세 가지 유형의 Collector는 Young과 Old Generation별 GC와 Full GC이다.
  1. Young Generation GC
  2. Old Generation GC
  3. Full GC
1. Young Generation GC

Young GC는 하나의 단계로 구성된다.
-XX:ParallelGCThreads=8 과 같이 옵션을 통해 Young GC를 수행하는 thread 갯수를 조정할 수 있음. 대부분의 old generation GC의 copy나 cleanup 등 stop-the-world 방식 동작들(initial mark, remark, cleanup, copying, young)은 이 thread들이 piggyback하여 실행한다.
gc log에는 [GC pause (young)]으로 표시됨
  1. Young GC pause (Stop-the-world)
    • Young GC는 단계가 지나면 young generation region의 객체들을 survivor region들로 copy(move)
    • Survivor region의 오래된 객체는 old generation region으로 이동
2. Old Generation GC

Old GC는 다섯 단계로 구성된다.
대부분의 단계는 필요 시에 Young GC 실행 시에 piggyback되어 실행되므로 Young GC의 parallel gc thread들이 실행한다.
다만 시간이 많이 걸릴 수 있고 stop-the-world가 필요없는 mark 단계는 별도의 쓰레드를 통해 실행된다.
-XX:ConcGCThreads=8 와 같이 옵션을 통해 Old generation marking 단계에 사용되는 GC 쓰레드 갯수를 조정한다.
gc log에는 young GC에 piggyback되는 초기 mark 단계는 [GC pause (young) (initial-mark)]으로 표시되고, 마찬가지로 young GC에 piggyback되는 copy/cleanup 단계는 [GC pause (mixed)]로 표시된다.

  1. Initial Marking Phase (Stop-the-world)
    • Old GC가 필요해지면 Young GC 때 함께 실행
    • [GC pause (young) (initial-mark)]
  2. Concurrent Marking Phase
    • 빈 region들을 찾아 표기하고 region별 live object 비율을 계산해둔다.
    • 이 region들은 바로 다음 Remark 단계에서 제거
    • 별도의 concurrent GC thread들이 실행
  3. Remark Phase (Stop-the-world)
    • 빈 region들은 삭제해서 free로 만든다.
    • 전체 region들의 live object 비율이 계산된다.
  4. Copying/Cleanup Phase (Stop-the-world)
    • 가장 빨리 청소가 가능한 live object 비율이 낮은 region들을 선택한다.
    • Young GC 때 선택한 region들을 청소한다.
    • [GC pause (mixed)]
  5. After Copying/Cleanup Phase
    • 선택된 region들의 compaction이 완료된 시점.
    • young과 old generation이 모두 cleanup되고 선택된 region들은 모두 새로운 region으로 compaction되어 위치한다.

3. Full GC
G1 GC는 가능하면 Full GC를 회피하기 위해 여러 가지 Young GC와 Old GC를 적절한 시점에 실행한다.
Young GC는 일상적으로 실행되며, Old GC는 young area와 old area 비율이 일정 값 이하로 떨어졌을 때 (즉, young area가 부족하게 되었을 때) 트리거되어 실행된다.
예를 들어 기본값으로 young과 old는 1:2의 비율을 가지고 있다. 따라서 old area 비율이 늘어나서 young area의 2배를 가지게 되면 old generation gc가 실행된다.
만일 Old GC를 통해서도 필요한 young area를 확보하지 못하게 되면, 어쩔 수 없이 Full GC를 실행하게 된다.
  • Single-threaded
  • Stop-the-world
  • 이때 permanent area cleanup도 실행 (즉, classloader unloading은 이때 일어남)

일요일, 5월 31, 2015

[자바] FileChannel에서 map을 하면 내부적으로 unmap은 언제 일어날까? Finalizer를 PhantomReference가 대체할 수 있나?

1. java.nio.FileChannel에서 map을 호출한 다음에 unmap은 언제 이루어질까?

언뜻 생각해보면 FileChannel에서 mmap을 호출하므로 FileChannel을 close할 때 명시적으로 unmap을 해주는 게 효율적인 구현이 아니었을까 생각이 들긴 합니다..
하지만, 실제 JDK 구현은 그렇게 하지 않았습니다.

openjdk v6 코드를 보면
{openjdk6}/jdk/src/share/classes/sun/nio/ch/FileChannelImpl.java 에 해당 구현이 되어 있습니다.

channel을 close하면 내부적으로 implCloseChannel 메소드가 호출이 되는데 여기에서는 mmap 관련한 일은 행하지 않습니다.
명시적으로 unmap을 하는 경우는 transferTo나 transferFrom이 호출된 경우 일시적으로 사용된 mmap을 바로 munmap해줍니다.

실제 MappedByteBuffer는 Unmapper라는 unmap을 위한 객체를 매번 따로 만들어서 해당 MappedByteBuffer에 대한 참조가 없으면 PhantomReference 방식으로 청소를 해줍니다.

코드를 쫓아가보면 결과적으로
{openjdk6}/jdk/src/share/classes/sun/misc/Cleaner.java 객체에 Unmapper 객체를 넘겨주는 형태입니다.

그냥 MappedByteBuffer 클래스에 finalize() 메소드를 구현하지 않고 PhantomReference 방식으로 복잡하게 처리한 것은 finalize() 메소드를 호출하는 Finalizer 쓰레드의 오버헤드를 줄이기 위한 것으로 보입니다. Finalizer 쓰레드에서 JNI 통해 munmap 시스템 콜을 하는 게 부담스러웠던 것입니다.

다시 문제로 돌아가서 왜 file channel을 close할 때 unmap을 하지 않았을까 생각해보면
원래 유닉스 시스템 콜에서도 fd를 close() 하는 것과 파일의 영역을 가상 메모리에 매핑한 것을 해지하는 munmap()은 별도의 시스템 콜이므로
만약 file channel은 계속 열어둔 상황에서 mapped byte buffer만 계속 만든다면 channel이 close될 때까지 munmap()이 호출되지 않는 문제가 발생하게 됩니다.
따라서 mmap을 실제로 호출하는 데 대응하는 객체인 MappedByteBuffer 객체를 해지할 때 munmap이 호출되는 게 맞는데 유감스럽게도 MappedByteBuffer 클래스(나아가 Buffer 클래스)에는 close()를 정의하지 않았습니다.
이렇게 함으로써 gc의 시점에 munmap이 호출되게 하는데 이것은 munmap의 시점을 정확하게 알 수 없는 문제가 있습니다.

2. Finalizer와 PhantomReference
Java NIO를 설계할 때 Buffer 계열의 메모리 해지는 gc에 맡기는 설계를 했기 때문에 MappedByteBuffer도 동일하게 구현을 한 것 같고, 좀 복잡하긴 하지만 효율 이슈로 finalize()를 override하지 않고 Cleaner라는 것을 사용합니다.

그렇다면 sun.misc.Cleaner는 어떤 쓰레드에서 실행되는가를 알 필요가 있는데 이 클래스는 JDK 내부적으로 Reference 클래스에서 사용하는 클래스로서 JVM이 "Reference Handler”라는 이름의 쓰레드를 만들어서 이 Cleaner 객체만 따로 처리합니다.

 ({openjdk6}/jdk/src/share/classes/java/lang/ref/Reference.java 코드 참조)

Finalizer 쓰레드는 JVM 내부에서 실행되는 JVM 엔진 쓰레드므로 각 자바 객체의 finalize 메소드를 호출하기 위해서는 JNI 호출을 해야 하는데 이 Reference Handler 쓰레드는 일반 자바 쓰레드이므로 바로 호출을 할 수 있는 장점이 있습니다.
전체 등록된 Cleaner 객체들은 하나의 linked list로 관리되고 Reference Queue에서 나올 때마다(즉, phantom referenceable해질 때마다) 자신을 list에서 삭제하고 등록된 Runnable을 실행해주는 방식으로 실행됨.

sun.misc.Cleaner 클래스를 사용하도록 다른 클래스들도 고안해볼 수 있긴 하지만, 어려운 부분은 해당 Cleaner에 넘겨줄 Runnable 객체가 원래의 객체를 참조하면 안된다는 점이 있습니다. (Strong Reference가 있으면 Phantom Referenceable 상태가 될 수 없으므로 memory leak이 될 것입니다).

finalize() 메소드는 물론 자신 즉, this에 대한 참조를 하고 있지만 자기 자신이고 JVM이 관리하므로 상관이 없습니다. 따라서 PhantomReference는 finalize() 메소드에 대한 완전한 대체를 할 수는 없습니다.

일요일, 3월 22, 2015

소프트웨어 혹은 SW 정책 관련하여 몇 가지 주장들에 대한 의견.

소프트웨어를 하는 사람으로서 의견을 표하고 싶은 몇 가지 소프트웨어 정책들이 있어서 얘기를 해보려고 한다.

소프트웨어는 국내에서는 스마트 혁명이라고 할 아이폰의 등장 이후 너무 갑작스레 중요한 화두가 되어버린 것 같다.

스티브 잡스의 말했던 기술(technology)과 인문 교양(liberal arts)의 교차로라는 말 또한 지나치게 이상하게 비틀려 확대 해석되는 일까지 생겼다.

그리고 IT 선진국이지만 Software는 그닥 선진국일 수 없는 국내 현실을 두고 여러 가지 의견과 진단들이 나왔다.


이러한 현상은 소프트웨어를 알지 못하는 (혹은 알 수 없고 알 필요도 없는) 공공 부문과 하드웨어 방식의 기업들에 의해 뒤틀린 또하나의 갈라파고스 현상이라고 생각한다.
현실에서 존재하지 않는 망상적인 "한국적 소프트웨어"라고 할까?

국내의 몇 가지 현상들에 대해 의견을 제시하려고 하는데 먼저 한 가지 확실히 해둘 것이 있다.
소프트웨어에 대한 문제는 국가의 경제 상태나 정책과 밀접하게 연결된 부분이 많아서 정치적인 문제가 개입될 수 있다.

내 의견은 정치적 관점과 완전히 무관하지는 않다. 하지만, 분명하게 해두고 싶은 부분은 내 의견의 가장 기본적인 출발점은 "사실이란 정치적 관점 등의 해석에 의해 바뀔 수 없다"라는 과학적 사고이다.

과학적 사고란 가설을 세우고 실험을 통해 검증 가능한 것들을 다룬다.
물론 실험이 어렵고 검증이 어려운 영역도 있지만, 정치적 관점이 사실을 정의하지 않는다는 것이다.

"어떤 정치적 입장에 유리한 것을 사실이라고 보는" 듯한 전도된 사고는 사절이다.

특히 SNS는 매우 전파력이 강하기 때문에 감성적으로 가까운 것들이 사실인 것처럼 쉽게 전파되는 경향이 있다.
감성적으로 전파되는 것들에 대한 논리적인 필터들 역시 쉽게 전파될 수 있으면 좋겠지만, 사람이란 모든 사안들에 대해 이성적 검증에 시간을 투입할 여유가 많지 않으므로 감성적 공감을 통해 전파하는 게 훨씬 우세하다.
나 또한 이런 부분에 많이 노출되어 있음을 부정하지 않겠지만, 적어도 소프트웨어에 관련된 부분은 감성적 판단보다는 내가 가진 소프트웨어에 관련된 논리를 기반으로 논리적인 판단에 의존하려고 노력한다.

한마디로 내 의견들이 대부분의 정치적인 사람들과 또 소프트웨어 관련된 일을 하는 사람들을 불편하게 할 수 있다는 것이다.

물론 SNS를 통해 내게 전달된 의견들에 대한 의견 불일치들이 이 블로그를 없는 시간 쪼개서 시작하게 된 이유이기도 하다.

1. 왜 소프트웨어가 중요한가
왜 국가적으로 소프트웨어가 중요하다고 말하는가? 그리고 창조경제를 말하는 정부 정책의 핵심이 왜 소프트웨어이어야 하는가?

창조 경제가 무엇인지에 대해 자세히 알지 못하고 또 현재까지 드러난 정책을 봐서는 실체가 있는지 알기도 어렵다. 다만 경제 정책의 큰 화두를 creativity로 잡았다는 데에 대해서 공감을 한다.

소프트웨어는 프로그램이다.
사람이 작성한 지시들의  집합이다.

왜 이것이 이렇게 중요한가?
왜 소프트웨어가 Smart와 Creative한 속성을 가지는가?

나는 사람이 하기 때문에 그렇다고 본다.
사람의 지혜에 따라 달라지기 때문이다.
소프트웨어는 상대적으로 적은 비용으로 프로그램을 교체할 수 있다. 유사 기능을 가진 다른 프로그램을 선택할 수도 있고, 버그를 수정한 패치를 적용할 수도 있고, 새로운 기능을 탑재한 버전으로 업그레이드할 수도 있다.

하드웨어를 업그레이드하는 것은 공장의 제조 라인을 수정하는 것부터 시작한다.
교체는 또 얼마나 어려운가?

소프트웨어 중에서도 애플리케이션 소프트웨어와 시스템 소프트웨어 혹은 플랫폼 소프트웨어는 구분된다.
시스템 소프트웨어는 애플리케이션 소프트웨어를 실행시켜주는 플랫폼 환경 역할을 하는 소프트웨어이다.

플랫폼 소프트웨어는 플랫폼의 규격을 준수한다면 어떤 애플리케이션 소프트웨어든지 설치하여 실행할 수 있는 능력을 가지고 있다.

애플리케이션 소프트웨어를 추가로 설치하면 무궁무진한 새로운 기능을 가질 수 있다는 뜻이다.

사람의 지혜가 더 지혜로울수록, 또 창의가 더 새로울수록 생각하지도 못했던 기능들을 더 가질 수 있는 게 소프트웨어이다.

물론 하드웨어 없이 시스템 소프트웨어가 실행될 수는 없고, 없는 하드웨어 기능을 사용할 수는 당연히 없지만 일단 하드웨어를 갖추면 시스템 소프트웨어도 기능을 업그레이드할 수 있으며, 원하는 기능을 갖춘 애플리케이션 소프트웨어를 언제든지 탑재할 수 있는 확장성과 유연성이 제공된다.

게다가 소프트웨어의 능력이 엄청나게 커지고 있다.
이 역시 사람들의 지혜의 발전이다.
사람의 인지, 판단 능력을 소프트웨어가 대체할 수 있을 가능성이 매우 높아질 정도로 소프트웨어 기술이 발전해왔다.

어떤 문제를 해결하기 위해 소프트웨어적인 접근을 할 때, 그 수단의 수준이 급격하게 높아졌다는 뜻이다.

하드웨어의 발전 또한 사람의 능력이 중요하지 않은 게 아니지만, 소프트웨어는 시작부터 끝까지 사람이 개입함으로 인해, 사람의 창의적 수준에 따라 발전 속도가 엄청나게 빠를 수 있고 또 그 다양성 측면에서 하드웨어와 비교할 바가 아니다.

다시 생각해보자. 왜 소프트웨어가 중요할까?
국가 정책 관점에서 소프트웨어 육성은 어떤 의미를 가질까?

산유국도 아니고 땅덩어리가 넓은 것도 아니지만 엄청난 교육열과 나쁘지 않은 수학적 두뇌, 집중력을 가진 민족으로서 어느 정도 기술 혁신이 포화 상태에 이르고, 차별적 우월성을 주장하는 데 한계에 이른 하드웨어 부분에 이어 새로운 미래 분야라고 한다면 소프트웨어가 중요한 역할을 하지 않을 수 있을까?

여태 우리는 소프트웨어에서 특별한 성취를 해오지 못했다. 하지만, 미래의 경쟁은 소프트웨어와 같은 창의적 영역에서 발생한다.
우리가 더 잘하지 못한다고 해서 포기해도 되는 게 아니다.
지금도 하드웨어와 소프트웨어의 융합이 여러 영역에서 진행되면서 차별적 우월성은 점점 더 하드웨어 기술이나 공정이 아닌 소프트웨어 특히 시스템 소프트웨어 영역에서 결정되고 있다.

단언컨대 미래는 점점 더 사람의 창의적 지혜가 중요한 영역이 더 큰 역할을 할 것이라고 생각한다.

창의적 지혜가 가장 많이 발휘될 수 있고, 쉽게 산업화될 수 있는 부분이 소프트웨어이다.

2. 무엇이 소프트웨어에서 중요한가
우리는 그다지 소프트웨어에서 잘하지 못했다.
국가가 투자를 적게 한 건 아니라고 생각한다. 다만 방법이 틀렸다.
소프트웨어가 성공한 나라는 미국, 핀란드, 굳이 하나 더 꼽자면 이스라엘 정도인 것 같다.

인도는 미국의 소프트웨어 백업 국가라고 얘기를 하지만, 아직 소프트웨어적으로 성공한 나라로 칭하기에는 이른 것 같다.
인도인들이 미국 소프트웨어 산업에서 점점 더 중요한 역할을 하지만, 정작 인도에서는 그닥 창의적인 소프트웨어를 만들지 못하고 있다.
SI 프로젝트를 열심히 하는 것은 알겠지만...
중국은 개개인들의 능력은 매우 대단하다. 소프트웨어 인구도 많고.. 하지만 아직 문화적인 이유로 그룹 창의의 수준에 이르지 못하고 있는 것 같다.

소프트웨어 중 가장 중요한 부분은 앞에서 언급한 플랫폼으로 사용되는 시스템 소프트웨어가 있고, 그외에 어떤 문제를 해결해주기 위한 솔루션으로서의 소프트웨어를 들 수 있다.

어떤 문제를 어떻게 풀 것인가?
어떤 사람은 복잡하지만 좀더 많은 경우에 동작하는 답을 찾기도 하고 어떤 사람은 단순하지만 특정 영역에서 더 잘 동작하는 답을 찾기도 한다.
독특한 아이디어가 들어가서 전혀 다른 답을 찾을 수 있는 것이 소프트웨어적인 해법들이다.

나는 소프트웨어의 문제 풀이 방식을 악제(惡題, wicked problem)의 방식으로 풀어야 한다고 본다. (다음 블로그 참고 : 소프트웨어 국가 정책을 악제(惡題, wicked problem)적 특성에 맞게)

소프트웨어는 사람의 집단적 창의력을 충분히 활용할수록 더 나은 솔루션을 만들 수 있는 영역이라고 생각한다.

경쟁력 있는 소프트웨어를 육성한다는 것은 집단적 창의를 갖춘 우수한 소프트웨어 팀을 많이 만드는 것이다.

단순히 창의는 소프트웨어만의 문제가 아니라 하드웨어든 융합이든 모든 영역에서 마찬가지라고 생각하지만, 소프트웨어에서 가장 큰 차별성을 만들 수 있다고 생각한다. 소프트웨어를 포함하는 융합에서도 마찬가지이다.

그럼 왜 우리는 성공하지 못했는가?
먼저, 수많은 시행착오를 통해 단련될 소프트웨어의 팀을 만들 때까지 기다려주지 않는다.

또, 그렇게 차별화를 만들 수 있는 우수한 두뇌들은 소프트웨어를 선택하지 않고, 의대, 법대를 선택해왔다.

일제 잔재와 군사독재 문화가 여전히 기업과 사회에 강하게 침투해 있어 경직된 조직 문화가 창의를 선택할 수 없게 만든다.

전문성을 갖춘 팀에서 내용을 가장 잘 아는 사람이 판단해야 하지만, 가장 모르는 사람이 판단하는 문화를 갖고 있다.
분업적 조직과 분업적 사고로 융합된 판단을 할 수 없는 조직 문화를 몇 안되는 국내 소프트웨어 기업에서도 선호한다.
즉, 기획 따로, 개발 따로인 문화이다.
기획에서 용역을 주면 개발을 해주는 식의 구조가 그나마 잘나간다는 소프트웨어 기업에도 만연해 있다.
기획부터 개발까지 기술과 고객 문화를 정확하게 공유하면서 최선의 결정을 내리는 문화가 전혀 없다. 사람의 결정이란 세부적 사항에서는 약하더라도 주요한 영역에서는 세부적인 부분까지 이해하고 전체적인 상들을 가지고 있어야 좋은 결정이 가능하다. 다른 사람의 머리를 빌어서 생각을 할 순 없기 때문이다.

모든 조직과 과정을 통해 끊임없는 feedback을 받아 진화시킬 수 없다면 소프트웨어적인 솔루션을 만들 수 없다.

3. 소프트웨어는 소프트웨어 공학이나 SI와 그닥 상관이 없다
소프트웨어와 소프트웨어 공학의 관계는 매우 특이하다.
많은 사람들은 소프트웨어 공학의 발전을 통해 좋은 소프트웨어가 나오는 것으로 오해하고 있다.
유감스럽게도 소프트웨어 공학은 소프트웨어에 크게 기여를 하는 학문이 아니다.
나는 이것을 이렇게 표현한다.
"소프트웨어 공학은 소프트웨어 품질의 하한을 보장하기 위한 학문이다."

하지만, 경쟁력은 소프트웨어 품질의 상한을 높임으로써 만들어지고, 이것은 철저하게 사람들의 창의(내 기준으로는 집단적 창의)에 의존한다.

우리나라 SW 국가정책의 많은 부분이 소프트웨어 공학을 적용하려고 애쓴다.
소프트웨어 시장이 없고, 고객이 없는 현실을 반영한다고 본다.
미국에서 국가가 소프트웨어를 만들거나, 소프트웨어 스타트업 육성을 위해 관여하겠다고 했을 때 옆에서 지원이나 잘하라고 실리콘밸리에서는 화를 냈다.

눈에 보이는 수치를 미리 표현하기 어렵고 예측하기 어려운 소프트웨어의 상한쪽 품질을 국가 정책이 해결하기는 어렵다.
그런 시장이 만들어지도록 진흥책을 써야지, 국가가 직접 소프트웨어를 만들겠다고 나서면 그 소프트웨어가 정말 경쟁력 있는 창의적 솔루션이 될 수 있을 것인지, 아니면 민간 영역에서 진정한 창의적 솔루션을 만들어도 시장에 들어오지 못하게 가로막는 걸림돌이 될 것지 예상을 못한다면 그건 참으로 무책임한 정책이 될 것이다.

앞의 논지에 따라 나는 다음을 얘기할 수 있다.
"SI나 단순 개발은 소프트웨어의 핵심도 경쟁력도 아니다."

물론 SI가 대규모의 프로젝트를 효율적으로 수행함에 있어 중요한 역할을 하고 SI가 무용한 것은 결코 아니지만, 소프트웨어의 핵심 경쟁력은 SI가 다루는 영역과는 거리가 있다.

4. 그들은 소프트웨어를 잘할 수 있을까?
이 질문은 참 껄끄러운 질문이다.

먼저 그들에 이미 소프트웨어 기업으로 성공해온 제니퍼소프트를 대입해보자.
개인적으로 제니퍼소프트를 정말 좋아하고 응원한다.
이원영 대표의 기업 철학을 정말 좋아한다.

다만, 이것은 내가 갖고 있는 우려이다.

제니퍼소프트가 이루어온 것들은 앞으로도 기술 혁신을 통해 계속 정진하지 않으면 금새 무너질 수가 있다.
너무 당연한 이야기이다. 그리고 그 기술이 SW 환경의 변화와 혁신이 가속되면서 금새 바뀐다. 어떤 소프트웨어 기업도 기술의 혁신 없이 존재할 수 없다.

소프트웨어 기업이 제품의 새로운 버전을 내놓거나 새로운 제품을 내놓는 것은 회사의 운명과 직결된다.
기술 변화를 잘 감지하고 준비하여,  글로벌 기업과 기술에서 경쟁할 수 있기를 기원한다.

회사의 복지 정책이 너무 유명세를 타면서 혹시나 내부의 기술 경쟁력에 소홀히 하지는 않나 하는 우려에서 언급해봤다.

화이팅!

소프트웨어 기업이 아닌 재벌 전자업체들도 스마트 혁명 이후 소프트웨어를 매우 열심히 하고 있다. 그들에 이들 전자업체를 넣으면 어떻게 될까?

나는 조급함과 공격적 목표의 차이를 얘기하고 싶다.
더 많이 알수록, 더 중요한 기술을 가질수록, 더 큰 지혜와 창의를 활용할수록 더 신속하고 나은 소프트웨어를 만들 수 있다고 생각한다.
그것과 조급함에 떠밀리는 것은 차이가 있다고 본다.

스마트한 소프트웨어를 만들 팀을 형성하였는가? 그들의 기술과 논리를 충분히 이해하고 의사 결정을 할 수 있는가?

내 판단으로는 아직 그럴 준비가 안된 것 같다. 정말 지금까지 대단한 캐치업 능력을 보여주긴 했지만 지속적으로 연착륙할 수 있을지 모르겠다.

5. 그외. 오픈 소스가 답인가? 인문학이 중요한가?
"오픈소스가 답이다."
나는 이 주장에 대해 좀 한심하다는 생각을 한다.  어느 문제에 대한 답이란 말인가?
소프트웨어 정책은 오픈소스가 답이라는 뜻이라면 소프트웨어 포기가 답이라는 뜻으로 이해가 된다.
그저 아파치와 같은 오픈 소스 재단의 몇몇 모듈에 핵심이 아닌 몇 개 버그들을 수정하는 커미터가 된다고 해서 대단한 일인가.
오픈 소스를 위한 잉여의 시간이 만들어지지 않는 국내 개발자들을 위해 국가가 일부 시간에 대해 책임져주겠다는 건지 무엇인지 모르겠다.
공개와 공유의 가치를 소프트웨어에 적용한 오픈 운동의 거대한 역할을 무시하자는 게 아니다.
시스템 소프트웨어 영역부터 다양한 소프트웨어들이 오픈되면서 선진 기술이 공유되고, 참조할 정보들이 풍부해졌다.
하지만, 그 공유된 기술을 기반으로 혁신할 생각을 하지 않고 오픈 소스를 사용하여 국가가 소프트웨어 솔루션을 직접 만들겠다는 논리로 이어지고 있어 더 황당할 뿐이다.
핵심은 오픈 소스를 그대로 사용하고 비핵심적인 툴들만 만들면 된다는 뜻인지?
더 나은 핵심 소프트웨어를 만들어 오픈으로 하든 클로즈드로 하든 기술의 혁신을 이루는 게 핵심이지, 외국의 잉여로 만든 오픈 소프트웨어들을 그냥 가져와서 쓰는 게 무슨 국가 발전에 도움이 되는가?
도대체 왜 그런 주장을 하는지 논거를 제시해주면 좋겠다.

"인문학이 중요하다"
나는 앞에서도 말했듯이 이 주장의 근거인 "liberal arts"가 인문학을 뜻하는지에 대해서 의문을 갖고 있다. B2C에서 사람을 이해하는 것이 중요하다는 측면에서 인문학이 중요하다는 점에 공감할 수 있다.
그냥 "사람이 중요하다"고 말하고 싶다.

소프트웨어를 하는 사람으로서 국가의 미래가 소프트웨어와 큰 관련이 있다는 생각을 한다.
정말 우리가 소프트웨어를 잘할 수 있을까 하는 의문도 갖고 있다.
창의적인 소프트웨어에 대한 이해가 국가 차원에서도 거의 없는 상황에서 또 과거의 성공적인 경험도 많지 않은 상황에서 굳이 해야 할 분야인가 하는 의문도 많이 있는 상황이다.

하지만, 점점 더 경쟁의 한계에 이르고 있고 자원을 팔아먹고 살 민족도 아닌데 (물론 지난 5년간 자원을 해외에서 찾아 팔겠다는 분이 계셨다. 결국 국민의 혈세만 천문학적으로 해외로 빼돌렸다) 기술의 숙련만으로는 고부가가치를 만들 수 없는 상황에서 창의적인 영역에서 소프트웨어와 융합을 다뤄야 하는 것은  피할 수 없다고 생각한다.

이 분야를 지금까지 해왔던 하드웨어적인 혹은 지극히 분업화된 너따로 나따로의 방식으로 접근한다면 미래는 매우 암울하다.

코딩을 교과 과정에 넣는 일도 갑론을박이 많았는데 나는 찬성한다.
나는 국민 모두의 교육 과정인 liberal arts의 범주에서 국사를 빼는 일도 반대하지만 수학이나 코딩도 매우 중요하다고 생각한다.
아이디어를 코드를 통해 구현해서 검증하는 교육이 논리적 사고에 큰 도움이 된다고 생각한다.