솔라리스 11 (Solaris 11) 설치 후 root 로그인 허용하기

Posted by taeho Tae-Ho
2014.10.01 14:32 운영체제

Sun Microsystems가 Oracle에 인수 합병된 후 국내 시장에서 Sun 서버의 시장 점유율은 체감적으로 형편없이 떨어졌습니다. 여러 고객사에 방문해 보면 기존에 Sun 서버를 사용하던 고객들도 대부분 IBM이나 HP로 돌아서는 분위기 였고 실제 서버보안SW를 설치하는 경우에도 Sun 서버는 기존에 Sun 서버를 주로 사용하던 고객사 이외에는 더 이상 Sun 서버를 도입하지 않는 분위기로 바뀐지 오래입니다.


하지만 노트북이나 조립서버에서 유닉스 환경의 데모나 테스트를 진행할 때는 그나마 인텔계열 CPU를 지원하는 상용 유닉스가 유일하게 Sun 뿐이기 때문에 아직까지는 Sun을 버릴 수는 없는 것이 현실입니다.


그러다 보니 VMWare에 Solaris 11을 설치해야 하는 상황이 생겼습니다.



솔라리스를 설치하는 과정에서 일반 계정을 하나 생성하라고 강제합니다. 그리고 기존의 설치 과정에서 root 계정의 비밀번호를 초기화(생성)해주던 과정은 사라졌습니다. 아마도 비밀번호가 없는 상태로 root 계정이 만들어지고 root 계정으로는 아무도 직접 로그인하지 못하도록 합니다. (콘솔에서도 로그인 불가)


이렇게 root 계정을 표면적으로 사용하지 못하도록 하는 것은 보안을 강화하기 위한 조치로 보입니다. 하지만 root를 직접 사용해야 하는 경우가 있기 때문이 root 계정을 직접 로그인할 수 있도록 설정하는 방법을 기록해 두고자 합니다.


솔라리스에는 Role이라는 독특한 보안 개념을 적용합니다. 그리고 root 계정을 직접 로그인하지 못하는 root Role로 지정합니다. 이러한 root Role에 대한 설정은 다음과 같이 /etc/user_attr 이라는 파일에서 설정합니다. 



root 의 타입을 일반 계정이 아닌 role로 선언함으로써 실제 사용자 계정이 아닌 Role(역할)로 선언합니다. 하지만 이것은 실질적인 보화를 위한 보호대책이라고 할 수는 없습니다. 엄연히 실제로 root 계정은 존재하고 주요 작업을 하기 위해서는 root 계정으로 Switch User를 해야하기 때문입니다.


위에서와 같이 운영체제 설치 과정에 생성한 계정(여기서는 castle) 계정의 맨 뒤에 roles 부분에 root를 지정합니다. 이렇게 되면 castle 이라는 사용자로 로그인한 뒤 sudo 명령을 통해 root 패스워드를 입력하지 않고 root 계정으로 SU가 가능합니다.


흔히 이것이 보안을 강화하는 방법이라고 생각하는 경우가 많습니다. 하지만 서버에 직접 root 계정으로 로그인하는 것 만을 차단할  뿐 실질적인 보안강화 효과는 없다고 보는 것이 옳습니다. 어차피 sudo 명령을 통해 root 로 전환한다면 전환 권한을 가진 계정의 비밀번호가 탈취되면 root 계정이 탈취되는 것과 동일하기 때문입니다. 게다가 castle 계정에서 root 계정으로 sudo를 통해 비밀번호 입력 과정없이 전환이 되는 치명적인 보안문제가 남게 됩니다.


어쨌든... root 계정의 비밀번호를 초기화(생성)하고 root 를 role이 아닌 계정으로 변경해야만 su - root 명령을 통해 root로 전환하거나 콘솔에서 root로 로그인할 수 있습니다.


다음과 같이 root 패스워드를 변경합니다.



1) 설치 중 생성한 계정으로 로그인

2) sudo su - 명령을 실행

3) 설치 중 생성한 계정의 비밀번호를 입력하여 root로 전환

4) passwd 명령을 통해 root 비밀번호 생성(초기화)


여기까지만 진행하면 su - root 명령으로 전환은 가능합니다. 하지만 아래 화면처럼 콘솔에서 직접 로그인은 되지 않습니다.



Role은 직접 로그인 할 수 없다고 씨부렁~~거립니다. ^^


다음과 같이  role을 변경해야 합니다.



root의 타입을 normal 로 변경합니다.


여기까지 진행하고 나면 user_attr 파일에서 root Role 라인이 없어지고 이후에는 root 계정으로 비밀번호 인증 후 로그인할 수 있습니다.


----

솔라리스 11 설치 후 기본 네트워크 설정 방법 참고 사이트

솔라나라 : http://www.solanara.net/solanara/solaris11

아루마루의 낙서장 : http://nagjang.tistory.com/11



신고
이 댓글을 비밀 댓글로
  1. 솔라리스 11 설치후
    root 로그인하기 잘 보았습니다.^^
    연휴 잘 보내셨는지요?
    행복한 시간 보내세요!
    • 교육준비하고 시연준비 하느라 바쁜 연휴였습니다...^^ 감사합니다...^^

프로세서와 프로세스의 차이 (processor vs process)

Posted by taeho Tae-Ho
2014.09.05 10:16 운영체제

IT 업종에서 일하면서 가끔 프로세서(processor)와 프로세스(process)를 구별하지 못하는 개발자나 엔지니어들을 종종 보게 됩니다. "그게 그거 아니냐.."거나 "구별할 필요가 있냐"라는 생각을 가진 사람들도 꽤 있습니다. 사실 구별할 줄 몰라도 일하는데 큰 지장은 없는 것이 사실입니다. 하지만 진짜로 비전공자라서...몰라서 구별하지 못하는 것이라면 공부하여 배우면 되지만 전자계산학이나 컴퓨터공학을 전공했음에도 불구하고 구별하지 못한다면... 정말 우리나라의 대학의 전산 관련 전공 계열의 교육과정은 심각한 문제가 있다고 단언하고 싶습니다. 그리고 한발 더 나아가 대학교 4년 동안 도대체 공부 안하고 뭘 한거냐고 따끔하게 혼내주고 싶습니다.


process .vs. processor프로세스와 프로세서



프로세서와 프로세스의 구별


프로세서와 프로세스는 엄연히 다른 존재입니다. 


Processor (프로세서)는 하드웨어적인 측면에서 "컴퓨터 내에서 프로그램을 수행하는 하드웨어 유닛"이다.  이는 중앙처리장치(Central Processing Unit)를 뜻하며 폰노이만 아키텍쳐에 의해 만들어졌다면 적어도 하나 이상의 ALU (Arithmetic Logic Unit)와 처리 레지스터(Register)를 내장하고 있어야 한다.


프로세서에 대한 정의입니다. 오래 전 혼자 공부했던 8008과 z80 같은 마이크로프로세서를 떠올리게 하는 정의입니다. 


이런 정의를 충족하는 것에는 매우 여러종류의 프로세서들이 있습니다. 네트워크 장비(라우터, 스위치, IP공유기, 스위칭허브 등)에 포함되어 있는 네트워크 프로세서, 디지털 미디어 기기(MP3, 디지털피아노 등)에 사용되는 DSP(Digital Signal Processor) 등 매우 다양한 종류의 특정 목적에 적합하게 설계된 전용 프로세서들이 있습니다. 반면에 노트북이나 데스크탑 또는 서버에 사용되는 프로세서들은 특정 목적이 아닌 범용(일반적인 다양한 목적)적으로 사용할 수 있는 범용 프로세서입니다.


프로세서는 하드웨어에만 사용되는 용어는 아닙니다. SW적으로도 의미를 가지며 프로세서라고 불리는 프로그램들도 있습니다. 


소프트웨어적으로 프로세서라 함은 데이터 포맷을 변환하는 역할을 수행하는 데이터 프로세싱 시스템(데이터 처리 시스템)을 의미하며 출력 가능한 인쇄물을 생성하는 워드프로세서도 프로세서라 부른다.


조금 애매하긴 합니다만 위의 범주에 포함되는 소프트웨어는 워드프로세서와 컴파일러, 어셈블러 등이 포함됩니다. 프로세서라는 용어의 정의가 명확하게 정의되기 훨씬 이전부터 관습적으로 프로세서라고 부르던 소프트웨어들을 넓은 의미의 프로세서에 포함시켜주는 분위기가 강합니다. 


결론적으로 프로세서는 CPU나 Microprocessor 라는 하드웨어를 말하는 것으로 그 범위가 점점 축소되어 명확해져 가고 있습니다.


반면 프로세스는 말 그대로 "절차(과정)" 입니다. 때문에 스스로 무언가를 처리하지 못합니다. 프로그램은 스스로 실행하면서 데이터를 입력받고 결과를 생성해 내니 "프로세서"라고 불러도 되지 않느냐라고 반문하는 사람도 있었습니다. 하지만 그것은 분명 틀린 논리입니다.


프로세스는 특정 목적을 수행하기 위해 나열된 작업의 목록이라고 생각하여야 합니다. 즉 프로그램이죠. 컴퓨터에서 프로그램은 프로그래밍 언어로 작성된 작업 수행 과정일 분입니다.프로그래머가 작성한 소스코드와 소스코드가 컴파일되어 기계어로 번역된 바이너리파일도 그저 작업 과정이 기록된 파일일 뿐입니다.


작업의 과정이 파일로 저장되어 있으면 그것을 "프로그램"이라고 부르고 메모리에 적재되어 실행 중 이거나 실행 대기 중일 땐 "프로세스"라고 구별하여 부를 뿐입니다. 즉 프로세스는 "메모리에 적재되어 프로세서에 의해 실행중인 프로그램" 이라고정의하는 것이 정확할 것입니다.


"프로세서에 의해 실행 중인 프로그램"의 의미를 이해해야 한다.


이 의미를 이해하려면 CPU의 동작 원리를 이해해야 합니다. CPU는 엄청나게 복잡한 현대 전자공학의 정수라 할 수 있습니다. 저는 중학교(?) 시절 오락실에서 본 8bit MSX 호환 컴퓨터에 푹 빠져 고등학교를 졸업하자 마자 Microprocessor를 혼자 공부했습니다. 혼자 공부하다 보니 분명 한계는 있었지만 CPU의 동작 원리에 대해 이해하는 좋은 계기가 됐었습니다. 


컴퓨터가 프로그램을 실행하는 과정은 매우 복잡하지만 프로세서와 프로세스를 구별하기 위해 가장 중요한 부분은 다음과 같은 순서를 이해하는 것입니다.


1. 사용자가 단축 아이콘 혹은 명령행에서 프로그램을 실행한다.

2. 파일로 저장되어 있던 프로그램은 메모리(램)에 로더(Loader)에 의해 적재(load)되고 처음으로 실행해야 할 기계어 코드가 저장된 메모리의 주소를 CPU의 명령주소(IP : Instruction Pointer) 레지스터에 저장한다.

3. 프로세서(CPU)는 IP 레지스터가 가리키는 메모리의 주소에서 (처음으로) 실행할 명령어를 인출(메모리에서 CPU로 가져오는)하여 명령 레지스터(IR : Instruction Register)에 저장한다.

4. IR에 저장된 명령을 실행하고 IP에 다음번에 실행할 명령어가 있는 주소를 저장한다.

5. 3~4를 프로그램의 끝까지 반복한다.


위의 과정이 프로그램이 실행되는 과정입니다. 사실 실제로는 백 배는 더 복잡한 과정이 있고 레지스터도 다양하며 계산할 것도 많지만 이 정도만 확실하게 이해하고 그 과정을 조금 더 스스로 공부해보면 충분합니다. 


즉, 프로세스는 CPU 입장에서 봤을 땐 파일로 저장된 프로그램이 디스크에서 메모리로 읽어들인, 즉 장소와 포맷만 바뀌었을 뿐 스스로 실행되는 살아있는(?) 것이라고 보기는 어렵습니다. 프로세스는 그저 CPU가 실행할 과정과 실행 시 참조할 데이터를 메모리(램)에 적재해 둔것에 지나지 않는다는 거죠. 즉 프로세스는 프로세서가 실행할 명령어와 데이터목록을 메모리에 읽어들인 것에 지나지 않는다 라는 것이죠.


결국 프로세스와 프로세서를 정확하게 구별하지 못하는 이유는 파일로 저장된 프로그램이 메모리에 적재(load)되고 CPU(프로세서)에 의해 프로세스에 명시된 명령어를 순서대로 CPU로 불러와 실행되는 과정을 정확하게 이해하고 있지 못하기 때문입니다.

신고
이 댓글을 비밀 댓글로
  1. 덕분에 프로세서와 프로세스의 구별에 대해
    알게되었습니다.^^
    행복한 금요일 보내세요!
  2. 하드웨어와 절차의 구분 설명을 잘해주셨네요.
    저도 개발자 이지만 이런부분을 대강대강 알고있는 부분이네요.
    좋은 정보 감사합니다.

크롬 임시파일 폴더 변경하는 방법 - 두번째 방법

Posted by taeho Tae-Ho
2014.07.18 09:25 운영체제

작년에 크롬 웹 브라우저의 임시파일 폴더를 크롬 바로기기의 "속성"에서 옵션으로 지정하는 방법에 대해 포스팅한 적이 있다.   보러가기 - http://blogger.pe.kr/296


그런데 최근 노트북을 예전의 이미지로 복원하고 크롬을 새로 설치한 뒤 그 방법이 먹히지(?) 않는 현상이 나타났다. 옵션에 아무리 캐시 디렉토리를 지정해도 동작하지 않는다.


크롬의 버전이 업데이트 되면서 해당 옵션이 변경되었는지 아무리 찾아도 나오질 않고 시간은 없고 해서 그냥 윈도의 도스창(cmd창)에서 명령어를 통해..유닉스로 치자면 심볼릭 링크를 걸기로 했다. 나중에 보니 이미 그런 방법으로 사용하는 분들이 꽤 있는 것 같았다.


크롬의 기본 캐시 폴더는 아래 창에 보이는 것 처럼 쫌....깊다...



CMD 창을 실행하고 다음과 cd 명령어를 통해 같이 크롬 캐시가 있는 폴더로 이동한다.



위의 화면 처럼 Cache 폴더가 보인다면 아래의 rd 명령(Remove Directory)으로 기존의 크롬 Cache 폴더를 삭제하고 미리 만들어 둔(반드시 미리 만들어 두어야 함) 크롬의 캐시폴더로 사용할 폴더를 지정하여 일종의 심볼릭 링크를 걸어준다.


기본 크롬 캐시 폴더 삭제하기

rd /s /q "%LocalAppData%\Google\Chrome\User Data\Default\Cache"


미리 만들어 둔 크롬 캐시 폴더를 바라보도록 일종의 심볼릭링크 생성하기

mklink /j "%LocalAppData%\Google\Chrome\User Data\Default\Cache" "D:\Chrome\Cache"


이렇게 한 뒤 크롬을 재실행하면 D:\Chrome\Cache가 크롬 캐시로 사용되기 시작한다. 


신고
이 댓글을 비밀 댓글로
  1. 오우 멋진 방법이에요. 램 디스크를 캐시 폴더로 지정하고 싶을 때 사용하면 되겠네요. ^^
  2. 질문이 있습니다.
    캐시 폴더를 삭제를 하고 램디스크 명칭이 R이라 D대신 R을 넣어 심볼릭 링크를 설정 했습니다.
    그런데 임시폴더가 램디스크쪽으로 가질 않고 계속 원래 위치의 캐시 폴더로 쌓입니다.
    해결법을 알려 주시면 감사 드리겠습니다.
    • 아..캐시폴더를 바꾸셨군요...
      저 같은 경우에는 그런 경우는 없었습니다.

      경로에 오타난 오류가 있는 것은 아닌지 확인하시고..
      그래도 안된다면 크롬의 버전이 다른 것은 아닌지 확인해주세요..
      저도 현재 최신 버전에서 테스트를 해보고 알려드리겠습니다.

      ----

      이 포스트를 쓸 때는 Windows 7 환경이었는데..
      현재는 Windows 8.1 환경을 쓰고 있습니다.
      크롬 버전은 43.0.2357.124 m (64-bit) 으로 최신버전이구요..
      일단 결과는 크롬 캐시의 변경이 잘 이루어집니다. 드라이브명은 관계 없는 것 같구요..

      오타가 아니라면 권한의 문제일 듯 합니다.
      다시한번 오타 여부 확인해주시고요..오타였다면 C: 드라이브의 원래 경로에 Cache 경로가 생성될 겁니다.
  3. 질문이 있습니다.
    주인장님이 올려주신 램디스크 설정법을 제외하고 나서 구글링 해본 결과 다른 방식의 설정법이 2개가 나왔습니다.
    http://egloos.zum.com/hanavy/v/11159428, http://nywj.net/?p=165 입니다.
    첫번째 것은 이해를 하지 못하여서 실행하지 못하였고 두번째 것은 설정은 하였으나 재부팅을 하면 캐쉬폴더가 제자리로 돌아옵니다.
    위 의 두방식과 주인장님이 해놓으신 방법의 공톰점과 차이점이 궁금합니다.
    그리고 캐시 폴더를 제외한 어플리케이션 캐시. 데이타 캐시,지피유 캐시, 스토레이지 폴더 또한 바꾸고 싶은데 방법이 있을까요?
    마지막으로 크롬 기반으로 둔 스윙 브라우저 또한 바꾸고 싶은데 위 방법으로 가능할까요?
    • 첫번째의 것은 크롬이 실행될 때 아규먼트로 기본 경로가 아닌 폴더를 UserData 경로로 사용하도록 크롬에게 전달해 주는 방법입니다. 때문에 다른 단축아이콘을 실행하거나 다른 브라우저나 프로그램에서 크롬을 실행할 경우에는 다시 기본경로를 사용하게 되는 문제가 있습니다. 이 첫번째에 꼼수~라고 나오는 것이 제가 올린 포스트와 두번째 방법입니다. (같은 방식이죠)

      이 방법을 꼼수라하는 이유는 크롬은 C: 드라이브의 기본 UserData와 Cache를 사용하려 하지만 해당 경로가 단축아이콘과 같이 일종의 링크여서 실제로는 D:\Chrome\ 과 같은 다른 경로로 리다이렉트 되는 방식이기 때문입니다. 하지만 이 꼼수는 앞의 방법과 달리 다른 브라우저에서 크롬을 호출하거나 다른 프로그램에서 크롬을 실행해도 UserData와 Cache 경로가 바뀐 곳으로 사용되는 장점이 있습니다.

      저도 첫번째 방식으로 사용하다가 언젠가 노트북을 포맷하고 Windows 8.1로 업글한 뒤 잘 적용이 안되는 듯 하여 두번째 방법으로 바꿔 사용하고 있습니다.

      마지막 질문의 해답은 설정법 두개 중 후자를 사용하시면 되겠네요... 두번째 블로그에 잘 설명되어 있는 것으로 보입니다.
      첫번째 방법 보다는 확실하게 두번째 방법을 권해드립니다.

      두번째 방법은 리부팅해도 다시 원복되지 않는 방법입니다. 해당 증상은 글만으로는 원인을 알 수는 없습니다.
    • 2015.08.04 13:36
    비밀댓글입니다
    • 만든 링크를 del 명령으로 지우고 mkdir 명령으로 Cache 폴더를 만들면 됩니다.

Sticky bit 란 무엇인가? (Unix 와 Linux 운영체제)

Posted by taeho Tae-Ho
2014.05.01 11:39 운영체제

유닉스와 리눅스에서 파일 퍼미션에 대한 공부를 하다보면 나오는 특수한 파일 퍼미션이 두개가 있다. 하나는 앞의 find 명령어에 대한 고찰(http://blogger.pe.kr/338)에서 조금 살펴본 setuid/setgid 이고 다른 하나는 이번 포스트에서 설명할 sticky bit다.


1. sticky bit 란?


유닉스 운영체제는 기본적으로 파일의 소유자가 아니면 해당 디렉토리 내의 파일을 지우거나 수정하지 못하도록 기본적인 umask를 설정한다. 하지만 딱~두군데 모든 사용자 계정이 파일을 만들고 수정, 삭제할 수 있는 디렉토리가 있다. 바로 /tmp와 /var/tmp다. 이 두개의 디렉토리는 퍼미션이 기본적으로 777로 설정되어 있어 누구나 임의의 파일을 생성하고 수정하고 삭제할 수 있다. 말 그대로 모든 사용자 계정이 사용하는 공용 디렉토리다.


그러다 보니... 이 두개의 디렉토리에 퍼미션이 777 퍼미션을 갖는 파일들과 디렉토리들이 생겨나게 되는데...문제는 이 파일들이 꼭 필요한 파일인지 알 수 없고 현재 사용중인지 아닌지를 판단하기 어렵다 보니 파일 퍼미션이 777인 파일들을 아무나 다른 소유자의 파일들을 지워버리는 문제가 생겨난다. 하지만 그 파일들이 현재 사용중인 파일이라면 서비스에 장애가 발생하게 되는 것이다.


그래서 등장한 것이 sticky bit 다.


sticky bit가 설정된 디렉토리 내에서는 


1. 퍼미션이 777인 파일에 대해서 파일의 소유자만이 삭제를 할 수 있다. (수정이나 실행, 읽기는 모두 허용된다.)

2. sticky bit가 설정된 디렉토리 자체도 소유자만이 삭제할 수 있다.

3. root는 다할 수 있다.


즉... 파일을 만든 계정과 root에서만 삭제할 수 있다는 뜻이다. 비록 파일의 퍼미션이 777이더라도 말이다.


2. 실제 테스트


[taeho@ncsd /]$ ls -l 

drwxrwxrwt   3 ncsd ncsd  4096 May  1 11:20 stickytest

[taeho@ncsd /]$ 

[taeho@ncsd /]$ 

[taeho@ncsd /]$ id              

uid=500(taeho) gid=500(taeho) groups=500(taeho)

[taeho@ncsd /]$ 

[taeho@ncsd /]$ rm -f stickytest

rm: cannot remove `stickytest': Permission denied        <--- 퍼미션이 777이고 sticky bit가 설정된 디렉토리 삭제안됨.

[taeho@ncsd /]$ 

[taeho@ncsd /]$ cd stickytest        <--- sticky bit가 설정된 디렉토리로 들어감.

[taeho@ncsd stickytest]$ 

[taeho@ncsd stickytest]$ ls -l

total 4

-rwxrwxrwx 1 ncsd ncsd    0 May  1 11:20 1.txt

drwxrwxrwx 2 ncsd ncsd 4096 May  1 11:11 test

[taeho@ncsd stickytest]$ 

[taeho@ncsd stickytest]$ rm -rf 1.txt

rm: cannot remove `1.txt': Operation not permitted      <--- 퍼미션이 777인데 소유자가 다르기 때문에 삭제 안됨.

[taeho@ncsd stickytest]$ 

[taeho@ncsd stickytest]$ rm -rf test

rm: cannot remove directory `test': Operation not permitted     <--- 퍼미션이 777인 디렉터리가 소유자가 다르기 대문에 삭제 안됨.

[taeho@ncsd stickytest]$ 

[taeho@ncsd stickytest]$ 


sticky bit를 특정 디렉토리에 지정해주기 위해서는...


$ ls -l 

drwxr-xr-x   3 ncsd ncsd  4096 May  1 11:20 stickytest      <--- 755 퍼미션의 테스트 디렉토리

$ chmod 1777 stickytest        <---- sticky bit 는 맨 앞의 1 임.

$ ls -l 

drwxrwxrwt   3 ncsd ncsd  4096 May  1 11:20 stickytest      <--- sticky bit 설정된 화면



이쯤에서 chmod 1777 에서 1은 sticky bit 인것은 알겠는데 왜 나머지 퍼미션을 777로 주는가?? 에 대한 의문이 생긴다면... 맨 앞의 내용을 다시 잘 읽어보기 바란다.


신고
Tags
이 댓글을 비밀 댓글로

쉘스크립트에서 이따금씩 사용되는 2>&1 이해하기

Posted by taeho Tae-Ho
2014.02.22 11:07 운영체제

이런저런 쉘스크립트를 보다면 스크립트의 문장 끝부분이 다음과 같은 구문을 종종 보게된다.


cat /tmp/error.txt  > /dev/null 2>&1


cat 명령은 error.txt 파일의 내용을 출력하는 명령이고...


> 는 리다이렉션으로 화면에 출력되는 내용을 > 다음에 지정한 파일로 보내는 것이니 /dev/null 로 결과를 보내고, 즉 화면에는 표시하지 않고...까지는 유닉스 환경을 다루어본 학생이나 엔지니어라면 쉽게 이해한다.


문제는 2>&1 이다.


흔히 "아~저건 에러메시지도 화면에 표시하지 않게하는 거지."라며 아는 척~~하는 사람들도 많다. 맞다. 정확하게 알고 있긴하다.


쉘스크립트를 작성하고 실행할 때 중간에 에러가 발생하게 되면 에러메시지가 화면에 고스란히 출력되어 보기에 썩~좋지 않기도 하고 에러가 많거나 계속 다른 메시지가 출력되면서 화면이 스크롤되어 에러를 확인할 수 없게 되는 경우가 있다. 그럴 경우 로그파일에 에러메시지를 기록하도록 하기 위해 2>&1 을 사용해 에러메시지를 로그파일에 기록하고 화면은 깔끔하게 유지하도록 한다.


하지만 2>&1이 의미하는 정확한 뜻을 이해하는 것이 엔지니어의 본분이 아닐까..??


파일디스크립터와 표준입력/표준출력/표준에러


C프로그래밍을 해본 사람들은 잘 알고 있어야 하는 것이 파일디스크립터다.(윈도에서는 핸들이라고 부른다) 프로그램이 수행되면 운영체제는 실행되는 프로그램에게 3개의 기본 파일디스크립터를 할당해준다. 그리고 그 프로그램이 내부적으로 다른 파일을 open하게 되면 운영체제는 4번째 파일디스크립터를 할당한다.


운영체제가 프로그램에게 할당하는 세개의 파일디스크립터는 다음과 같다.


 파일디스크립터

 설   명

 0

 표준 입력 (standard input)

 1

 표준 출력 (standard output)

 2

 표준 에러 (statndard error) 


이해가 되는가? 만약 프로그램을 작성하고 프로그램 내부에서 파일을 열게 되면 파일디스크립터는 3부터 할당된다.


프로그램이 실행되면 운영체제는 프로그램에게 어디로부터 입력을 받고 연산결과를 어디로 출력하고 에러가 발생하면 에러를 어디로 출력할지 정해주어야 한다. 그 기본값이 바로 표준 입력, 표준출력, 표준 에러다. (표준입출력장치 및 표준에러장치라고 부른다.)


표준입력


표준입력장치는 기본적으로 키보드다. 프로그램이나 쉘에서 표준 입력장치를 변경하지 않으면 프로그램은 키보드 입력을 표준입력으로하여 기다린다. 


예를 들어 다음과 같이 cat 명령을 실행하면..

$ cat /etc/hosts

# Do not remove the following line, or various programs

# that require network functionality will fail.

127.0.0.1               localhost.localdomain localhost

192.168.100.10        ncsd    loghost

cat 명령은 프로그램 내부적으로 첫번째 인자(아규먼트)로 지정된 파일을 사용하도록 프로그래밍되어 있다. 따라서 cat 명령 다음에 지정된 /etc/hosts 파일을 열고 내용을 출력한다. 하지만 cat  명령 뒤의 인자인 /etc/hosts를 지정하지 않고 cat 명령만 입력한 뒤 실행하게 되면 cat 명령은 표준입력장치인 키보드로 부터 입력을 받도록 프로그래밍 되어 있다.


즉 다음과 같이 동작한다.

$ cat             <-- 파일명 없이 실행

abcdef           <-- 키보드에서 입력하고 엔터키를 입력

abcdef           <-- 키보드에서 입력받은 내용을 화면에 출력한 부분

keyboard input         <--- 역시 키보드로 입력한 내용

keyboard input         <--- 키보드에서 입력받은 내용을 화면에 출력

                     <-- 다른 키 입력없이 엔터만 입력

                      <-- 엔터만 출력

$                   <-- ctrl + c 키를 눌러 종료


그리고 cat은 표준출력장치로 자신에게 기본적으로 할당된 표준출력장치를 사용하도록 되어 있다. 변경하지 않을 경우 모든 프로그램들은 모니터 디바이스를 표준출력장치로 사용하도록 되어 있다. 그래서 위의 예제에서 모두 결과가 화면에 출력되는 것이다.


표준 입력장치 변경하기


쉘에서 표준 입력장치를 변경하는 방법은 두가지가 있다. 바로 리다이렉션과 파이프다. 먼저 리다이렉션을 사용하여 표준 입력장치를 변경하는 예제다.

$ cat /etc/hosts

# Do not remove the following line, or various programs

# that require network functionality will fail.

127.0.0.1               localhost.localdomain localhost

192.168.100.10          ncsd    loghost

$ cat < /etc/hosts

# Do not remove the following line, or various programs

# that require network functionality will fail.

127.0.0.1               localhost.localdomain localhost

192.168.100.10          ncsd    loghost



리다이렉션을 사용하여 표준 입력장치를 변경할 때는 일반적으로 명령어 뒤에 < 기호를 입력하고 장치명(파일명)을 사용한다.


 위의 두 예제의 실행 결과는 동일하다. 하지만 프로그램 내부의 동작은 전혀 다르다는 것을 이해해야 한다. 


cat/etc/hosts 명령은 cat 명령에게 /etc/hsots 파일을 열도록 지정한 것이다.

하지만 cat < /etc/hosts 명령은 아규먼트 없이 실행될 경우 사용하도록 지정된 표준입력장치인 키보드(standard input)를 /etc/hsots 라는 파일로 바꾸도록 지정하여 파일의 내용을 표준입력으로 리다이렉트 받아 실행한다.


결과는 같지만 내부적인 수행과정은 전혀 다른 것이다.


표준출력과 표준출력장치 변경


표준 출력도 마찬가지다. 표준입력은 < 기호를 이용하여 변경했다. 표준 출력은 > 기호를 이용해 변경한다.

따라서 맨 앞에서 예를 든 cat /tmp/error.txt > /dev/null 이 바로 cat 명령의 표준 출력을 화면이 아닌 /dev/null로 바꾼 것이다. 즉 cat /tmp/error.txt 명령에 의해 화면에 출력될 error.txt의 내용을 화면으로 출력하지 않고 /dev/null 이라는 파일로 출력하는 것이다. (하지만 /dev/null은 운영체제에서 사용하는 블랙홀과 같은 장치파일이다. ) 


하지만 문제는 cat/tmp/error.txt > /dev/null 은 error.txt 파일이 있다면 아무런 메시지를 화면에 출력하지 않고 정상 동작하지만 error.txt 파일이 없다면 아래화면 처럼 에러메시지를 화면에 출력한다. 

$ cat /tmp/error.txt > /dev/null

cat: /tmp/error.txt: No such file or directory



위의 예제는 표준 출력만을 바꾼 것이다. 그런데 이 문장은 사실 무언가가 생략된 문장이다. 표준 파일 디스크립터에는 출력에 대한 디스크립터가 2개다. 표준 출력과 표준 에러가 그것이다. 따라서 위의 예제는 다음과 같이 쓰슨 것이 정상이다.

$ cat /tmp/error.txt 1> /dev/null

cat: /tmp/error.txt: No such file or directory


리다이렉션 기호인 > 앞에 1, 즉 표준출력을 의미하는 파일 디스크립터를 써주는 것이 정확한 표현이다. 다만 파일 디스크립터를 생략하면 두개의 출력 디스크립터 중 표준 출력이라고 묵시적으로 약속이 되어 있는 것이다.


자 그렇다면 이 포스트의 맨앞에서 나왔던 다음 문장을 이해해보자.

cat /tmp/error.txt  > /dev/null 2>&1


/dev/null 까지는 이해했을 테고....


뒤의 2> 도 이해가 되어야 한다. 즉 2번 파일디스크립터인 표준에러다. 즉 표준에러 출력을 > 다음의 장치(파일)로 변경한다는 의미다. 그런데 &1 이 사용되었다. 1은 표준 입력/출력/에러 장치에서 표준 출력을 의미한다. 즉 표준출력의 출력장치로 지정된 장치(파일)을 표준에러 출력장치로 함께 사용한다는 의미다. 즉 에러가 발생하면 에러 메시지를 /dev/null로 리다이렉트한다는 의미다. 앞에서 표준 출력장치(1)이 /dev/null로 변경(리다이렉트)되었기 때문이다.


예제에서는 /dev/null 을 표준출력장치로 리다이렉트 했지만 실제 쉘스크립트를 작성할 때는 스크립트의 수행 중 발생되는 출력과 에러를 기록하는 로그파일로 지정하는 것이 바람직하다고 하겠다. 그래야 스크립트의 실행결과와 에러를 정확하게 파악하고 디버깅을 할 수 있기 때문이다.


이해가 안된다면 이해가 될때까지 반복해서 읽어보고 테스트를 해봐야 한다.



이전포스트 보기 : 쉘스크립트에서 사칙연산과 문자열 자르기



신고
이 댓글을 비밀 댓글로
  1. 유익한 글이네요 ^^

Debian linux에서 SecureCRT를 사용할 때 한글깨지는 문제 해결

Posted by taeho Tae-Ho
2013.12.02 22:22 운영체제

이전 포스트에서 구입한 NAS인 My Book Live를 들여다 보면서 발견한 문제 중 하나가 내가 즐겨 사용하는 SecureCRT에서 한글이 깨지는 것이었다. 무심고 LANG 환경변수..Locale...터미널 등등.. 평소 알고 있던 상식(?)을 동원해 봐도 한글깨짐 문제는 해결이 되지 않고 아래 화면처럼 보인다.



이 문제를 해결하기 위해서는 일단 Debian 리눅스의 locale을 아래와 같이 맞춰주어야 한다. 최근엔 대부분 UTF-8 캐릭터셋(로케일)을 사용하므로 EUC-KR 보다는 UTF-8로 설정한다.



만약 로케일이 ko_KR.UTF-8로 되어 있지 않다면 다음의 명령을 실행하여 로케일을 맞춰주면 된다.


# dpkg-reconfigure locales


로케일을 맞췄다면 이제 SecureCRT에서 UTF-8 환경의 한글출력을 설정해줄 차례다.


"Session Options"로 들어간 뒤 아래 화면처럼 Appearance 메뉴로 간다.



폰트를 한글폰트로 선택한다. 폰트에 무슨 차이가 있는지는 정확히 알지 못하지만 내가 즐겨 사용하던 Fixdays 폰트는 UTF-8 환경의 한글을 출력해주지 못하는 것 같다.  그리고 중요한 것이 화면 하단의 "스크립트" 옵션이다. 여기를 반드시 "한글"을 선택해주어야 한다. 그렇지 않으면 한글이 모두 깨진다.



폰트와 스크립트를 모두 한글로 선택한 뒤 확인을 클릭한다. 


그리고 Character encoding에서 UTF-8 을 선택한다.



그리고 나서 접속하면 깨지던 한글이 감쪽같이 정상적으로 표현되고 입력도 된다.



PUTTY도 마찬가지로 폰트의 제약이 심한편이다. SecureCRT와 Putty 모두 UTF-8 환경에서 한글을 사용할 땐 일부 폰트를 사용하지 못한다.


그 이유가 대충 감은 잡히는데 정확한 이유가 무엇인지 궁금하다.



신고
이 댓글을 비밀 댓글로

안드로이드 개발자 옵션 보이기와 감추기 (안드로이드 4.3 이상)

Posted by taeho Tae-Ho
2013.12.02 22:22 운영체제

넥서스7 1세대와 2세대 그리고 넥서스 5에서부터 새롭게 지원되기 시작한 ART(Android RunTime)을 사용하기 위해서는 안드로이드의 개발자 환경 옵션에 들어가 ART와 Dalvik 중 하나의 런타임환경을 선택해주어야 한다. 


물론... 아직 안정화 되었다고 단정하긴 이르다. 일부 앱에서 오류가 발생한다는 소식이 들리기도 하고 처음 나온 솔루션이 항상 그렇듯 일정기간 동안은 실 환경에서의 테스트와 버그 수정이 필요하기 때문이다.


그런데.. 안드로이드 4.2 (또는 4.3 ??) 부터는 그 이전의 안드로이드 설정에서 보이던 "개발자 옵션"이 사라졌다. 아무리 설정을 뒤져도 "개발자 옵션"이 없다. 구글에서 "개발자 옵션"을 숨긴 이유는 정보보호 때문임이 자명하다.


검증되지 않은 apk 파일을 다운받아 설치할 경우 해킹, 개인정보 유출 등의 문제가 발생하기 때문이다.


하지만 숨겨진 개발자 옵션을 다시 보이게 하는 방법도 있다. 무척 간단하다. 그리고 개발자 메뉴를 다시 사라지게 하는 것도 매우 간단하다. 그 과정을 따라해 보자.


1. 일단 설정으로 간다. 개발자 옵션 메뉴가 보이지 않는다.


2. 태블릿 정보 메뉴로 들어간다. 맨 아래에 "빌드 번호" 정보가 보인다. 자.. 빌드번호를 빠르게 다~다~다~다~ 터치한다.


3. "개발자가 되셨습니다." 라는 메시지가 보인다. 오~~정말 개발자가 된다면 얼마나 좋을까...


4. 다시 설정 메뉴로 가보면 "개발자 옵션"이 보인다.


5. 개발자 옵션에 들어가 보면 "런타임 선택" 이라는 메뉴가 보인다. 기본적으로 "Dalvik 사용"으로 되어 있다. 이 메뉴에 들어가 보면 ART와 Dalvik 을 선택할 수 있다.


그런데 일부 사용자들은 "개발자 옵션"에서 옵션을 바꾸고 다시 "개발자 옵션" 메뉴를 사라지게 하고 싶을 수도 있다. 


1. 사라지게 하기 위해서는 "애플리케이션" 메뉴로 들어간 뒤 "전체"로 간다. 그리고 "설정" 애플리케이션을 선택한다. (설정도 하나의 프로그램이다.)


2. "설정" 앱정보에 들어가면 중간에 "데이터 지우기"가 보인다. 설정에서 선택한 옵션들이 저장된 용량이다. 이 데이터를 지우면 "설정"에서 변경한 옵션값들이 초기화 된다. 따라서 일부 설정 데이터가 초기화될 수 있으므로 "주의!!!"해야 한다. 지운 뒤 다시 확인하면 "개발자 옵션"이 사라져있을 것이다.



신고
이 댓글을 비밀 댓글로

안드로이드 속도가 아이폰보다 느릴 수 밖에 없는 이유와 구글의 숙제

Posted by taeho Tae-Ho
2013.11.15 11:02 운영체제

아이폰과 안드로이드의 속도 경쟁은 결국 32bit와 64bit 운영체제의 논쟁으로까지 번지는 형국이다. 하지만 그 싸움에서 안드로이드 진영은 애플을 이길 수 없다. 그 이유는 안드로이드의 앱 구동 체계의 구조적 문제 때문이다.


안드로이드는 리눅스 운영체제의 일종이면서도 사용자가 사용하는 앱은 모두 Java 언어로 개발된다. Java로 개발된 앱의 소스파일은 바이트 코드로 컴파일되기 때문에 운영체제가 직접 실행하는 것이 불가능하다. 왜냐하면 Java에서 컴파일된 바이트코드는 java Run-time 이라고 하는 실행환경(가상의 운영체제)에서만 읽고 해석(Just-In-Time 컴파일)이 가능하기 때문이다. 그리고 이러한 역할을 수행하는 것이 안드로이드에서 지원하는 앱구동 환경인 달빅(Dalvik)이다.


하지만 iOS는 앱이 기계어로 컴파일되어 저장소에 파일로 저장되어 있다가 사용자가 앱을 실행하면 곧바로 메모리에 올려져 운영체제에 의해 실행된다. 즉 안드로이드 처럼 앱과 운영체제의 중간에 존재하는 달빅과 같은 JIT 컴파일러가 필요없다. 이런 차이점은 바로 안드로이드의 앱 개발환경이 Java 이고 iOS의 앱 개발환경이 Object-C라고 불리는 C언어 환경이기 때문에 발생하는 차이다. iOS의 오브젝트C는 C언어로 작성된 앱의 소스파일을 아이폰의 운영체제인 iOS가 직접 읽어 메모리에 적재(loading)하고 곧바로 실행할 수 있도록 기계어코드(목적코드 혹은 Object-Code)로 만들어 저장소에 저장된다.


이 두가지 앱 구동 환경을 이해하기 쉽게 표시하면 아래그림과 같다.




간단한 그림의 표현만으로도 "안드로이드 스마트폰이 메모리도 더 크고 CPU도 더 빠른데 왜 아이폰보다 느린지"를 이해할 수 있을 것이다.


안드로이드와 애플의 64bit 전쟁.


앞에서 살펴본 스마트폰의 운영체제와 앱구동환경의 차이로 인해 최근 논란이 되고 있는 64bit 지원 논쟁에서 애플은 64bit 지원에 대해 자신감을 보이고 있는 반면 안드로이드를 만드는 구글은 멈칫하며 주저하는 미묘한 입장차이를 보이고 있기도 하다.


애플은 iOS와 오브젝트C 개발환경 그리고 CPU까지 모두 스스로 만들고 있으며 64bit CPU (AP : Application Processor라고도 부름)개발과 64bit iOS개발, 그리고 64bit 오브젝트C의 개발이 모두 하나의 작업처럼 진행될 수 있기 때문에 현재의 기술로서 64bit를 지원하는 것은 그리 어려운 일이 아니다. 게다가 32bit 오브젝트C로 개발된 앱의 64bit 포팅도 충분히 가능하다.


하지만 구글의 입장은 매우 복잡하다. 


리눅스 운영체제부터 64bit로 전환해야 하고 그 위에서 구동되는 Java는 Oracle에서 만들고 있으며 앱의 개발환경은 또 다른 곳에서 개발되고 있고 앱의 구동환경인 달빅의 64bit 포팅도 여러가지 문제로 인해 쉽지 않은 입장이다. 


여러 자유(?)진영의 합작품인 안드로이드가 64bit 지원이라는 복병을 만나 잠시 주춤하는 모습을 보이고 있다. 어찌보면 구글은 아이폰의 대항마였던 안드로이드를 만들면서 가장 쉬운길이었던 두가지의 선택, 즉 운영체제로서 리눅스를 선택한 것과 개발환경 및 앱 운영환경으로 가장 범용적이고 많은 개발자를 확보할 수 있었던 Java를 선택한 댓가를 64bit 환경의 지원이라는 과제 앞에서 치르고 있는지도 모르겠다.


어쩌면 구글은 64bit 문제로 인해 장기적으로는 안드로이드를 버리는 계획을 내부적으로 수립하고 있을지도 모른다. 그리고 그 대안으로 크롬(Chrome) OS를 밀어줄 것이 확실시 된다.


Dalvik vs ART(Android Run-time)


하지만 구글은 당장 안드로이드를 버릴 수 없기 때문에 현실적인 판단을 할 수 밖에 없다. 그 결과로서 구글은 안드로이드의 앱 구동에 대한 부정적인 이미지를 벗기위해 성능개선에 매달렸고 새로운 앱 구동환경 즉 런타임환경을 새롭게 만들었다.


구글은 최근에 출시한 넥서스5에서 Dalvik을 대체할 새로운 앱의 구동환경으로 내놓은 ART가 그것이다. 보다 빠른 앱의 구동을 지원하는 ART는 이 포스트를 올리는 현재시간 기준으로 넥서스5에서만 사용이 가능하다.



구글이 나름대로 안드로이드의 성능개선을 위해 많은 노력을 하고있긴 하지만 언제까지 지원을 아끼지 않을지는 알 수 없다. 그리고 "리눅스-Java-앱"의 3계층 구조 자체를 뜯어고치지 않는 이상 아이폰의 성능을 쫒아가는 것은 거의 불가능하다고 보여진다.  하지만 그러기엔 너무 먼길을 왔다. 아마도 그래서 구글이 크롬을 밀어줄 것 같다는 생각은 더욱 확실해진다.


관련포스트 : 아이폰은 정말 폐쇄적인가?

관련포스트 : C언어를 독학으로 공부한 이야기와 C언어를 공부해야하는 이유.

신고
이 댓글을 비밀 댓글로
  1. 흥미로운 글 잘 읽었습니다. 다른 부분은 동의하지만 크롬OS로 갈아탄다는 것은 상당히 어려운 일인거 같습니다. 안드로이드에서 구동 중인 여러 서드파티 앱들을 버려야만 한다는 것인데 구글이 과연 그런 결단을 내릴런진 의문입니다. 또한 HTML5 기반으로 돌아가는 크롬 앱들의 퍼포먼스 또한 안드로이드보다 나을지 장담할 수 없기도 하고요.
    • 물론 구글이 안드로이드를 버리고 크롬OS를 모바일 플랫폼의 주력OS로 갈아타는 것이 쉽지는 않겠지만 데스크탑과 모바일의 크로스플랫폼에 더근접하기 위해서는 어쩔 수 없는 선택이라고 봅니다. 크롬OS가 모바일과 데스크탑에 올라간다면 당분간은 안드로이드와 병행지원이 되지 않을까 싶습니다. 하지만 장기적으로 봤을 땐 안드로이드는 개발주체가 너무 산만하게 많고 복잡한 구조라서 오래 끌고갈 OS는 아니라고 보여집니다.
  2. 우와! 멋진 글이네요 ^ ^
    안드로이드도 좋고 iOS도 좋아하는데, 안드로이드가 거의 완성이라는 느낌에도 아이폰의 속도는 따라잡기 힘들다고 생각하고 있는데, 요로한 내용이 있었네요.
    혹시 모바일용 크롬OS가 나오나다면 요즘 또 식어버린 모바일에 급 관심이 갈 것 같기는 합니다. ㅎㅎㅎ ^ ^;;;
  3. 안드로이드에 64비트 도입은 그리 문제가 되지 않습니다. 생각보다 자바 계층의 오버헤드는 많지 않습니다. 애플이 64비트로 이동하면서 더 바빠진 쪽은 인텔입니다.
    • 안드로이드는 리눅스 이지만 ARM 계열로 포팅되면서 SMP의 지원측면, 64bit 지원 측면, 대용량 메모리의 지원 등 에서 많은 어려움을 겪고 있지요. Dalvik을 버리고 새로운 런타임인 ART를 구글이 새로 만든 것도 비슷한 이유 때문이라고 보면 됩니다. 이는 근본적으로 CPU, OS, Java 등을 모두 각기 다른 벤더에서 만들기 때문에 발생한다고도 볼 수 있지요. 결국 누구 하나에 의해서 아키텍쳐를 혁신할 수는 없기 때문에 안드로이드는 급변하는 하드웨어 환경에서 도태될 수 밖에 없는 운명이라고 보여집니다.
      그래서 구글은 그러한 어려움에 대비하여 크롬OS등 자체적인 생태계 구축을 위해 노력하고 있다고 보시면 됩니다. 나무를 보지 않고 숲을 보면 쉽게 이해할 수 있으실 겁니다.
    • mog422
    • 2013.12.15 13:15 신고
    이미 리눅스 커널은 64bit 폴랫폼을 충분히 지원하고 있습니다. (arm64는 어떤지 잘 모르겠지만요) Dalvik 이던 ART던지간에 앱을 실행하는 런타임 자체만 arm64에서 돌아갈 수 있게 지원을 해준다면 문제가 없을거 같은데요.
    • 리눅스 자체는 64bit가 잘 지원되지요. 하지만 ARM 계열에 포팅된 안드로이드의 경우 SMP의 지원이 부족하고 여러 제약사항으로 인해 그 위에서 구동되는 Dalvik에 대한 업그레이드 등의 문제로 구글이 어려움을 겪고 있는 것으로 압니다. 그래서 구글이 자체적으로 아예 새로운 런타임인 ART를 만든 것이구요.
  4. 오브젝트C가 아니라 오브젝티브C 입니다 ^^* 좋은 글 고맙습니다.
    • 행인235
    • 2013.12.15 21:12 신고
    개인적으로 지적하고 싶은 점이 여러개 있네요.
    1. JIT의 개념과 용어 정의가 틀렸습니다.
    2. 자바 바이트코드와 달빅 바이트코드는 서로 다릅니다.
    3. 바이트 코드를 사용하는 이유가 플랫폼(비트수를 포함해서)에 상관 없이 쓰기 위함이기 때문이고, JIT이 적용된 VM은 전체 실행타임에서 평균적으로 바이트 코드도 기계어와 유사한 성능을 냅니다.
    4. 안드로이드는 자바 형식을 빌려 바이트 코드를 달빅 바이트코드로 재컴파일 하므로 오라클과 아무 상관 없습니다.(이런 구글의 무단 차용 때문에 오라클과 법적 문제는 있었습니다만)
    5. 안드로이드 자체의(제조사 문제 이전에) 64비트 지원이 늦어지는건 C로 구현된 안드로이드 기본 라이브러리들을 포팅해야 하기 때문이지 협력 문제가 아닙니다.

    전제로 놓으신 부분들이 대부분 잘못된 정보라 신뢰성이 떨어지네요;
      • 행인235
      • 2013.12.15 21:16 신고
      추가로 달빅을 두고 ART를 만든건, 안드로이드를 느긋하게 준비하던 와중에(1.4~1.6) 아이폰의 출시로 인해 제조사들의 요구로 급하게 안드로이드 버전을 올리며 반년만에 달빅에 JIT을 추가하는 등 급하게 만들어 졌기때문에, 이를 처음부터 제대로 재설계하고 개선하기 위함이지 64비트 이슈와는 상관 없습니다.
    • 1. 틀린점을 구체적으로 이야기해주세요. 저는 고전적인 JIT의 구조를 설명한 것입니다. 너무 민감하게 반응하시는 듯 하네요. ^^ 무조건 틀리다, 무조건 다르다라고 이야기하는 것은 억지일 수 밖에 없습니다.
      2. pure java의 바이트코드와 달빅코드가 조금 다르다는건 압니다만 이 글의 주제가 두 코드의 차이를 이야기해야 할만큼 깊이 있는 주제는 아니라고 생각됩니다.
      3. cpu의 애플리케이션 실행속도는 백만분의 일초를 따져야할 만큼 미시적인 세상의 이야기 입니다. 가상머신 위에서 인간의 체감속도를 기준으로 비슷하다고 이야기 하는건 다른게 아니라 틀린거라고 생각됩니다. art던 dalvik이던 바이트코드는 네이티브코드의 속도를 따라갈 수 없습니다. (많이 따라잡긴 했습니다만.) 더군다나 하드웨어를 직접 제어하는 부분에서는 네이티브코드를 쓸 수밖에 없지요. 그리고 크로스플랫폼의 완벽한 지원은 아직까지도 멀었다고 보여집니다. 제아무리 자바소스라할지라도 다른 플랫폼으로 넘겼을 때 100% 정상적으로 구동이 되지는 않습니다. 더군다나 하드웨어에 의존하는 기능이 많을 수록 말이죠.
      4. 왜 구글과 오라클이 라이센스 문제로 법적인 다툼을 할까요?? 그리고 다른 많은 vm 업체들도 오라클과 라이센싱을 체결합니다. 그들의 VM이 java와 java vm과 아무런 관계가 정말 없을까요? 결코 아무런 상관이 없지 않으며 java vm의 기반을 그대로 사용하고 변형한 것이기 때문입니다.
      5. 안드로이드의 경우 멀티코어를 아직도 제대로 지원하지 못하고 있습니다. 일반 앱개발자들은 이를 잘 모르고 있죠. 작년인가?? 인텔이 이 문제를 이슈로 제기 하기도 했구요. (물론 영업적 목적이지만요.) 64비트 지원 문제는 자바나 달빅의 문제이기 이전에 cpu와 os를 제공하는 구글과 리눅스 그리고 cpu 제조사간의 협력이 이루어져야 해결될 문제임이 분명합니다. 이것 저것 64비트에서 지원해야할 까다로운 문제를 빼버리고 포팅하게 되면 CPU의 성능을 제대로 사용할 수 없습니다. 포팅은 했되 안하니만 못한 포팅이 되는거죠.

      사실..이글을 이렇게 많은 분들이 읽으리라곤 생각하지 못햇습니다. 그리고 작은 차이를 갖고 꼬투리를 잡으시면 사실 제대로 반박할만한 실력을 갖추고 있지도 못합니다. 그저 폭넓은 관점에서 안드로이드의 문제를 지적하고 싶었기 때문에 쓴 글임을 이해해주시고 읽어주셨으면 합니다.

      감정적인 대응은 서로에게 스트레스만 줄 뿐입니다.
    • 레보맨
    • 2013.12.15 22:06 신고
    윗분말씀에 동감입니다. 추가로 크롬 OS가 안드로이드보다 더좋은 퍼포먼스를 기대할수있다는 근거가 있어야 저런 결론으로 수렴될수 있을텐데요...
    • 크롬OS의 성능까지는 제가 잘 모르고 쓴글이 맞습니다. 하지만 안드로이드보다는 좋지 않을까요?? 최신버전을 써보신 분이 댓글달아 주시면 좋겠네요.
    • calming
    • 2013.12.15 22:52 신고
    근거가 하나도 없는 허무맹랑한 이야기네요. 어디서 들었다라는 식으로 이런 말도 안되는 글을 쓰다니...
    • ㅎㅎ 안드로이드를 무척 사랑하시나 봅니다만..
      이런 댓글은 그저 본인이 인격적으로 덜 성숙되었거나 삐뚤어진 심성을가진 사람이라는 것을 인증하는 것 밖에는 되지 않습니다.
    • 행인2
    • 2013.12.16 02:04 신고
    잘은 모르지만 퍼포먼스를 위해 NDK 나 JNI 를 활용한다고 들었는데요. 서드파티 개발자의 빠른 개발을 도모하기위해 달빅과 같은 런타임을 이용하지만 필요하다면 리눅스의 *.so 타입으로 직접 핵심 모듈을 개발하여 동작도 가능 한걸로 알고있습니다. 유니티 3D 엔진 내부에 보면 리눅스 라이브러리와 윈도우 라이브러리를 같이 쓰는걸로 보이더군요.
    • .so 파일은 Unix/Linux에서 지원하는 Shared Object 파일임을 나타내는 일종의 확장자같은 것입니다. 윈도의 DLL과 유사한 것이죠. 하지만 so 파일은 navtive 코드파일입니다. 다른 플랫폼으로 넘어갈 경우 전혀 동작하지 않죠. java에서 so 파일을 만들어 쓴다는 것 자체가 이미 바이트코드, java가 추구하는 의미가 퇴색된다는 것을 의미합니다. JNI나 NDK는 네이티브 코드를 java와 같은 jit 언어에서 사용하기 위한 수단을 제공하는 것입니다. 그렇기 때문에 JNI나 NDK를 사용해서 성능을 높아진다는 것은 결국 native 코드를 이용해 성능을 높인다는 의미이며 또한 java가 크로스플랫폼을 100% 완벽하게 지원하지는 못한다는 것을 의미합니다.
      하지만 이러한 것을 따지는 것은 큰 의미가 없습니다. 어떠한 솔루션으로도 100% 완벽한 소스코드의 크로스플랫폼 호환성을 보장하는 것은 기술적으로 거의 불가능에 가깝기 때문입니다. 불필요한 논쟁을 할 이유는 없다고 보여집니다.
    • 하하하하하하하하
    • 2013.12.16 09:55 신고
    암요. 개발툴, AP, OS를 모두 개발하고 있으면

    64bit 지원은 "그리 어려운 일이 아니다." 지요. 하하하하... 하하하하하하하... 하하하하하하하하하하하하하하핳.... 단어 선택에 너무 짙은 허세가 느껴져서 그냥 웃어봅니다.
    • ㅎㅎㅎ 제가 개발하는 것도 아닌데 허세까지야~~ ^^
      안드로이드와 iOS의 상대적인 비교를 그렇게 절대적으로 평가해주시니 몸둘바를 모르겠습니다. 저도 개인적으로 애플의 iOS를 그리 좋아하지 않는 사람입니다.~
      GNU 만세~~ ^^
  5. 한창 배움에 굶주리는 대학생입니다.
    본 포스팅과 댓글을 읽다가 한가지 궁금한 것이 있어 여쭈어봅니다.
    요즘 안드로이드 앱들도 달빅을 거치는 문제와 자바의 하드웨어 제어 문제로 NDK나 JNI를 사용하여 C와 java를 섞는다던지 하기도 하는 걸로 알고 있습니다.
    (랄까 저도 특강때 이렇게 들은 것이 맞나 헷갈리지만요..)
    또한 NDK나 JNI를 떠나 델파이(구 오브젝티브-파스칼)를 통해 c만으로 짠 프로그램과 앞서거니 뒷서거니 하는 처리속도(동작에 따라 평균보다 더 빨라지거나 느려질 수도 있으므로)로 처리할 수 있게끔 지원하고 있는 걸로 알고 있습니다.
    여기서 제가 궁금한 것은 델파이로 제작된 앱이 자바 언어나 오브젝티브-c 기반인 os 환경에서 동작하기 위해서는 네이티브로 빌드가 될 것 같은데요.

    바이트코드의 앱과 네이티브코드의 앱의 차이가 많은 편인가요?
    또, 네이티브 앱의 경우 호환성이 떨어진다고 하셨는데 이유가 있나요?
    델파이의 최신판 기준(XE5) 앱 빌드시 안드로이드에서는 조금 무거운 느낌이 있는데 네이티브로 빌드하더라도 결국 안드로이드는 달빅 머신을 거쳐야만 하는 구조인건가요?(애플제품에서는 오브젝티브-c로 한듯 제 속도가 나온다네요)
    • NDK와 JNI는 java의 한계를 극복하기 위한 솔루션입니다. Java는 특정 하드웨어에 종속된 기능을 사용하기 위해 java의 순수함을 일정부분 포기한 것이지요. 하지만 포기라기 보다는 현실적인 해결책을 찾기 위한 노력이라고 보는게 더 옳을 겁니다. NDK는 Java(여기서 자바란 안드로이드 프로그래밍을 포함함)에서 사용하기 위해 만들어 놓은 C/C++ 라이브러리고 JNI란 NDK와 Java를 연결시켜주는 프로그래밍 요소입니다. 때문에 NDK와 JNI를 사용한다는 것은 C/C++에서 컴파일된 Native Code를 사용하는 것입니다. Pure Java는 아닌 셈이지요. (사실 Pure Java냐 아니냐를 따질 필요는 없습니다.)

      델파이(Delphi)는 제가 90년대 중반에 처음 써봤던 언어인데요.. 그전에는 Turbo Pascal을 조금써봤구요. 델파이도 컴파일언어입니다. 델파이는 Pascal 언어의 문법을 따르는 객체지향형 컴파일언어 입니다. 일부 포인터도 사용할 수 있는 C와 비슷한 수준의 언어죠. 따라서 속도차이도 크지 않습니다. C와 델파이(저는 델파이를 그냥 파스칼이라고 생각하고 싶네요)는 동일하게 컴파일과정을 거쳐 네이티브코드를 생산하기 때문이죠. (C가 조금 빠르다는 평가가 있었습니다. 그럴 수 밖에 없습니다. 두 언어를 써보면 이해하게 됩니다.)

      예를 들어 C언어와 델파이와 비주얼베이직은 모두 컴파일 언어입니다. 즉 소스코드를 작성하고 컴파일하고 링킹 과정을 거치면 스스로 실행가능한 실행파일(네이티브코드)이 생산됩니다. 그렇다면 세 언어로 완벽하게 동일한 기능을 수행하는 언어에 따라 최적화된 200라인의 정도의 코드를 작성했을 때 컴파일하고 링크되어 생산된 네이티브코드가 동일할까요? 네이티브코드란 기계어코드를 말합니다. 세개의 기계어코드가 동일할 까요?

      이 세개의 기계어코드 중 어느 것이 빠르냐는 결국 컴파일러가 최적화된 기계어코드를 생산해 내느냐 아니냐의 차이라고 보시면 됩니다. 그렇다면 이쯤에서 조금 고민한 뒤 무릎을 치셔야 합니다. ^^
      어떤 언어냐를 떠나서 기계어에 가까운 로우레벨 프로그래밍이 가능한 언어로 작성된 소스코드를 컴파일 했을 때 최적화된 네이티브코드가 생산되는 건 당연한 결과겠죠. 사람이 이해하기 쉬운 수준의 프로그래밍언어로 작성된 소스를 컴파일할 때는 컴파일러가 기계어로 전환하기 위해 더 오랜 시간을 소비하게 되고 당연히 사이드이펙트로 부가적인 코드들을 더 넣게 됩니다.

      소스코드와 컴파일된 기계어코드간의 차이가 가장 적은 언어는 어셈블리입니다.
      어셈블리언어는 명령코드(C나 델파이 자바로 치자면 함수???쯤??)가 이론적으로 기계어와 1대1 매핑이 되기 때문에 번역 과정이 무척 단순하죠. 그래서 어셈블리를 기계어로 전환해주는 번역기는 컴파일러라고 하지 않고 어셈블러라는 별도의 이름으로 부릅니다. 어셈블리는 기계어와 1대1로 매핑되기 때문에 CPU의 아키텍쳐에 따라 따라 사용하는 명령어가 모두 다릅니다. 즉 인텔 i5에서 사용하는 명령어와 인텔80386에서 사용하는 명령어 세트가 다릅니다. C언어는 두 CPU의 명령어 차이를 이해하지 않아도 되죠. 하지만 어셈블리로 프로그래밍을 한다면 두 CPU의 명령어 세트의 차이를 이해해야만 더 빠르고 효과적인 프로그래밍을 할 수 있는 경우가 발생합니다. ^^ 이부분을 이해하셔야 합니다. 왜 그런지요...

      그 다음으로 최적화된 기계어코드(네이티브코드)를 생산하는 것이 전통적인 C언어입니다. C와 C++은 다릅니다. 예를 들어 동일한 기능을 수행하는 코드를 전통적인 C언어로 작성했을 때와 C++의 클래스를 이용해 상속과 생성자, 소멸자 등의 개념을 적용해 작성했을 때 과연 어느 쪽이 작고 빠른 네이티브코드를 생성해줄까요? 당연히 C입니다.

      델파이는 C와 유사한 수준일 겁니다. 다만 델파이도 전통적인 구조적프로그래밍만을 지원하는 오리지널 pascal 이라면 C와 비슷하겠지만 객체지향개념을 C++과 동일하게 적용한다면 아마도 C++ 수준의 속도를 내는 네이티브코드를 생산해주리라 예상됩니다.
      (제가 테스트를 해보진 않았으니... ^^)

      java의 경우 조금 차원이 다릅니다. 네이티브가 아닌 byte code를 생산해주고 그 byte code를 다시 네이티브로 번역한 뒤 실행하니까요. 당연히 바이트코드를 네이티브로 번역할 때의 효율성이 그 속도를 좌우한다고 봐야겠죠...

      금융권과 대기업들의 업무시스템이 대부분 Java로 만들어져있지만 속도가 중요한 모듈들은 아직도 C와 같은 컴파일 언어를 사용하는 경우가 많습니다. 최근 계정계 시스템을 메인프레임에서 Unix로 다운사이징을 시도하는 국내 넘버1급의 은행의 경우 메인프레임에서 사용하는 코볼(cobol)언어를 그대로 Unix에서도 사용할 계획이라고 하죠. Java로 바꾸는 것은 엄두를 못내고 있는데 전환도 어렵고 오래걸리지만 "성능"도 우려스럽기 때문이라는 이야기가 있습니다. 눈에 보이는 체감속도가 중요한 부분에서는 Java가 많은 부분 뛰어난 성능을 보이지만 눈에 보이지 않는 미시적인 부분에서의 속도는 네이티브를 따라갈 수 없습니다.

      호환성의 경우 델파이로 제작된 앱을 java에서 사용하기 위해서는 네이티브코드인 DLL이나 SO 형태 즉 라이브러리로 생성이 되어야 합니다. DLL이나 SO 로 생성된 네이티브 코드는 독립적으로 실행은 불가능하지만 그 안의 함수나 객체를 다른 자바 앱에서 호출해 사용할 수 있도록 해줍니다. 당연히 DLL이나 SO는 네이티브코드구요 이 네이티브코드를 호출하는 것은 다른 네이티브코드나 java 모두 가능합니다. 이런 형태가 바로 NDK와 JNI 죠.

      바이트코드와 네이티브코드의 앱은 속도면에서 큰 차이가 있구요. 그 이유는 앞에서 설명한바와 같습니다.

      네이티브 앱의 호환성이 떨어진다는 이야기는 컴파일러가 CPU 플랫폼에 종속적이기 때문입니다. 네이티브 코드는 기계어입니다. 따라서 기계(CPU)가 달라지면 실행이 불가능하다고 보면 됩니다. 물론 i5 CPU의 기계어와 Atom CPU의 기계어는 기계어 수준에서 호환성이 높기 때문에 거의 대부분 호환이 됩니다.(가상화 부분이나 멀티미디어 등에서 호환이 안되는 경우가 있습니다.) 하지만 i5 에서 컴파일된 네이티브코드(기계어코드)는 ARM이나 PowerPC, Sparc 등 다른 벤더의 CPU에서는 실행이 안되겠죠. 하지만 바이트코드는 물리적인 CPU가 아닌 Sun(지금은 오라클)에서 만들어주는 가상머신에서 가상머신이 구동되는 물리적인 CPU에 맞게 네이티브코드로 번역을 해서 java 가상머신이 대신 실행해 주는 구조이기 때문에 "플랫폼 독립적이다"라는 이야기를 하는 겁니다. 즉 플랫폼 구분하지 않기 때문에 호환성이 높다라고 이야기할 수 있는 거죠.

      도움이 되셨기를 바랍니다.
    • 아! 정말 감사드립니다.
      사실 도서관에서 책을 뒤져 읽어봐도 잘 이해가 되질 않았는데 이렇게 자세히 설명해 주셔서 너무 감사드립니다!
      답변에서 많은 부분이 - 질문 외의 궁금점까지 - 뚫린 기분입니다.
      그전에는 그저 언어 특성상 그렇다 정도로만 알았는데, 왜 언어별로 같은 동작이라도 차이가 나게 되는 지도 알게 되었구요.

      네이티브가 난해하다 라며 싫증을 내는 아는 애가 있어 네이티브가 뭔가 했는데 사실은 이미 네이티브 프로그램을 저는 쓰고 있었네요.
      SSE3 와 같은 시피유 정보를 볼 때마다 궁금했던 부분도 그 이유를 알겠습니다.

      그렇다면 최신 CPU라도 이전 세대의 CPU에 탑재된 명령어 세트로 빌드되었다면 이전 CPU에서도 동작을 하는 것인가요?
      또 네이티브가 컴파일러가 설치된 CPU에 종속적이라면 배포되는 프로그램의 경우 어느 CPU에서 동작할 지 알 수 없는데 그런 경우에는 어떻게 빌드되는건가요?

      제가 요즘 델파이를 한번 살펴보는 이유는 저도 잘 알지는 못했으나 파스칼로 불리울 당시의 문제점이 많이 개선되어 좋아졌다고 한번 배워보라는 타대학 교수님의 추천으로 관심이 있었거든요.
      그런데 툴이.. 너무 비싼게 흠입니다만..음..
      80, 90 년대의 파스칼과는 여러면에서 많이 달라졌다고는 하지만 저 역시 당시에 쓰이던 파스칼은 써보지 않았으니..(써본분 말씀으론 껍데기만 같고 델파이와 파스칼을 별개의 언어로 보는게 옮다는 분도 계시네요)
      그런데 델파이도 결국 SO나 DLL 라이브러리 형태로 생성되어 자바에서 호출하는 식으로 쓰인다고 하셨는데 다른 작품들을 보면 그게 아닌거 같습니다.
      자바에서 호출을 한다면 그 부분에 대한 코드도 작성되어야 할 것 같은데 아직까진 제가 델파이를 학습하면서 그런 부분은 보지 못하였고 델파이를 인수한 엠바카데로에서도 단일 코드로 순수 네이티브를 지원하는 유일한 플랫폼이라며 강조하는걸 보니 달빅을 아예 거치지를 않는건가 하는 의문이 있었거든요.
      이 부분은 좀더 공부해서 안드로이드로도 시도해보면 다시 확인해봐야 겠습니다.
    • 아~델파이가 많이 달라진 모양이네요. SO나 DLL 형태가 아닌 코드를 생성해준다면.. 어떤 방식인지 감이 오지를 않네요.. ^^ C에 관심을 가지면서 파스칼이나 델파이에는 관심을 갖지 못했거든요.. 일반적인 형태가 아닌 java와 조금더 밀착(?)한듯 하네요. 하지만 중요한건 개발속도와 성능개선을 위해 개발자들이 엄청난 노력을 한다는 거죠. 그래서 어떤 새로운 개념과 아이디어가 나올지 알 수 없고..그 모든 것을 다 머리속에 넣을 수는 없다는 거죠. 항상 열린 마음으로 새로운걸 받아들일 준비를 해야하는게..IT 업종에서 일하는 사람들의 숙명이죠.. ^^

      컴파일러의 옵션에 보면..(예전에 본 기억이 있는데..) 기준 CPU를 어떤걸로 할건지를 선택하는 옵션도 있었습니다. 하지만 구형 펜티엄CPU와 윈도XP에서 코딩하고 컴파일한 실행하일이 대부분 수정없이 최신 i7과 윈도7에서도 잘 돌죠.. 하드웨어도 마찬가지지만 운영체제도 그렇구요..대부분 하위호환을 보장하는 것이 기본입니다. 물론 상위기종에서 하위기종에 없는 명령어세트를 사용하도록 상위기종 CPU기준으로 컴파일했다면(당연히 컴파일러도 상위기종 CPU의 명령어세트를 사용해 컴파일하도록 기능이 갖춰져있어야 겠죠..) 하위 기존 CPU가 장착된 윈도에서 실행하려면 당연히 실행되지 않겠죠... ^^

      파스칼이 많이 좋아졌나 보네요..제가 처음 파스칼을 배울때도 C언어보다 더 구조적 프로그래밍에 적합한 언어다...라고 해서 C보다 먼저 파스칼을 공부했었거든요.. 지금은 다 잊었지만..ㅋㅋ
      그리고 안드로이드에서도 제가 알기론 달빅이나 ART를 거치지 않는 C로 작성하고 컴파일된 프로그램을 돌릴 수 있는 것으로 알고 있습니다. 안드로이드도 리눅스인데... C로 컴파일한 프로그램을 실행할 수 없다는건..말이 안되겠죠.. ^^

      공부 열심히 하셔서... 좋은 성과 얻으시길 바랍니다..
    • 감사합니다!
      바쁘신 와중에 갑작스런 질문에도 답변을 해주셔서 감사드립니다.
      더욱 공부에 정진하여 저 또한 이쪽에 한 팔을 거들 날이 오면 좋겠네요.
      좋은 하루 되시고 종종 들러 여러 가지 정보를 참고하도록 하겠습니다!
    • 2014.08.03 01:47
    비밀댓글입니다
    • ART도 Dalvik과 마찬가지로 자바런타임의 일종입니다. 다만 Dalvik이 애플리케이션이 실행될 때 마다 Java Byte코드를 Native 코드로 매핑하기 위해 번역을 하죠.. (쉽계 얘기해서..) ART는 앱이 실행(java에서는 load가 더 적합한 용어죠)될 때 ART가 앱의 번역 된 Native코드를 저장해 두었다가 다음번 실행 시 참조하여 빠르게 실행하는 구조입니다. 그래서 앱이 실행될 때 딜레이타임을 줄이는 방식이죠. 그 이외에는 크게 개선된 사항은 없는 것으로 알려져 있습니다. 아마도 앱을 다운받아 설치하고 실행하면 최초 실행 시 번역된 Native 코드(실제 Native코드인지 캐시인지는 모르겠지만)를 따로 보관하는 것으로 보입니다. 때문에 번역된 내용을 저장하기 위해 저장소를 더 사용하거나 아니면 리부팅하기 전까지만 메모리에 번역된 내용을 저장할 수 밖에 없기 때문에 저장소 혹은 램을 더 사용할 수 밖에 없겠죠..
      사실 운영체제와 자바의 기본을 제대로 배웠다면 대충 ART 장점에 대해 듣는 순간 이정도는 바로 캐치해야 합니다. dotbin 님은 금새 눈치채시고 물어보시는 거라 생각됩니다. ^^
      • 2014.08.26 15:27
      비밀댓글입니다
  6. 어쨌든 안드로이드 5.0이 나와 버렸군요.

    1. 힘든 64비트 지원 -> 이제 잘 됩니다. 더해서 공식적으로 x86도 지원합니다. 승리의 ART

    2. 인터프린터라서 느림 -> 이제 AOT라서 설치시 컴파일(기계어, 머신 코드를 생성) 합니다.

    거창하게 제시하셨던 숙제를 1년 만에 모두 해결해 버렸으니... 글 내려 주세요

    이런 잘못된 정보가 인터넷에 남아 있으면 않됩니다.
    • 저는 본문에서 64비트의 지원이 불가능하다고 언급한적이 없습니다. 여러 ap제조사와 구글이 어렵고 힘든 과정을 거쳐야 한다고 했죠. 그 과정은 쉽지 않습니다. 수년이 걸리는 걸 보지 않으셔나요 ? 반면 애플은 폐쇄적인 그들만의 아키텍쳐로 인해 오래전에 완료했습니다. 그 사실만은 인정해야죠. 님의 말대로 삼성은 아직도 그 힘든 작업을 마무리하지 못했고 롤리팝에서의 지원여부를 공개하지 않고 있습니다. 무엇이 원인이고 무엇이 결과인지 본문을 보고 판단하세요. 글의 요지를 잘 살펴보시기 바랍니다.

      자바는 컴파일된 바이코드를 각기 다른 플랫폼에서 재컴파일 없이 실행가능하게 하는 이식성을 목표로 개발된 언어입니다. 요즘의 자바만 보셔서 모르시겠지만 과거엔 잠시나마 분명 가능했습니다. 하지만 속도의 개선을 목표로 여러 플랫폼에서 그런 완벽한 이식성을 포기하게 됐죠. 이식성의 의미를 엄격히 이해하시길 바랍니다.무엇을 개발하든 이거 봐주고 저거 봐주는 유연함?은 때때로 치명적인 문제를 야기할 수도 있습니다. 엄격히 말해 aot나 art는 속도를 얻기 위한 fake 입니다. 그런 fake로 인해 이식성은 더욱 손상된 것이죠. 하지만 그런 fake가 잘못이라거나 해서는 안된다는 이야기는 절대 아닙니다. 기술분야에서는 때론 fake가 정답일 수도 있으니까요.. 다만 fake가 가져올 여파를 분명히 고려해야 한다는 겁니다.

      지금 님의 글은 분명 자바 추종자의 글입니다. 자바가 느리다. 자바의 이식성이 현재들어 많이 손상됐다는 글은 100% fact입니다. 대한민국이 망할놈의 나라면 이민가십시오. 당신의 토론 불가한 태도가 바로 망할놈의 자세입니다.

      언제 봤다고 불쌍하다느니 사실이 아닌 글을 내리라느니 버릇없는 글을 쓰면서 비난하나요? 그리고 아무데서나 아무주제에나 세줄요약 같은 되도 않는 말을 쓰지 마시기 바랍니다. 그런 말은 디씨나 오유나 일베 같은 가십을 다루는 사이트에서나 쓰시길 바랍니다.

      당신은 자바의 이슈를 논하기 전에 어디엔가 버려둔 온 예의부터 되찾기를 바랍니다. 다음부터는 예의 없이 쓰는 댓글은 예고 없이 삭제할 것임을 알려드립니다.
  7. 글 잘 읽었습니다. 덕분에 작년 몇 개월 동안 자바와 안드로이드를 공부하며 고민했던 부분들을 정리할 수 있는 기회가 되었습니다. 많은 것을 얻어 갑니다. 감사합니다.

    그리고 댓글들을 읽다 보니 타인을 전혀 배려 안하는 분들이 너무 많다는걸 세삼 느낍니다! 사람들 저마다 자라온 환경과 머릿속에 박혀 고착화된 지식이 다르며 그걸 표함함에 있어도 "아"가 다르고 "어"가 다르거늘... 조금 그러네요! 그냥 저 처럼 세상의 10%는 좋은 사람, 80%는 저 같은 평범인, 그리고 나머지 10%는 몰상식한 사람이구나 라고 여기시고 마음에 두시지 말길 바랍니다.
    • 저도 깊이 있는 지식이 있는 것은 아닙니다. 그래도 도움이 되셨다니...그저 기분이 좋습니다~~
      그리고 별로 신경 쓰지 않습니다~ ^^ 즐거운 하루~하루 되시길 바랍니다.
  8. 읽고나니. 13년도 글이군요. 제목이 자극적이여서 댓글이 불바다인가 봅니다 하하.

    본문에서 장기적으로는 안드로이드를 버리고 크롬OS로 갈 것이다. 라고 하셨는데 현재 시점에서 생각이 변화하시진 않으셨는지 궁금합니다. 물론 제시점에서도 크롬OS는 구글이 생각하는 미래를 위한 발판이고 그러한 의지가 보입니다. 하지만 안드로이드 생태계가 이젠 너무 광범위해지고 커졌습니다. 구글은 계속해서 안드로이드 웨어/오토/롤리팝 등을 차례차례 발표하고 있구요.

    때문에 저는 크롬 OS와 안드로이드가 가는 방향이 다르다고 생각합니다.
    윈도우가 터치스크린을 고려한 윈도우 8에서 윈도우 10으로 회귀하듯. IOS 와 OSX가 공존하듯
    PC와 모바일 운영체제에는 UX 적인 차이가 존재한다고 생각합니다. 그리고 이것을 하나의 운영체제에 자연스럽게 담는것은 어려운일이죠.

    물론 제가 안드로이드쪽 개발을 하고있어서 시점이 이러한 것 일수도 있겠지만요.
    (사람은 무의식적으로 보고싶은것만 보게된다고하니)
    • 말씀하신 것이 맞습니다. 전략이란 것은 시장상황에 따라 변하는 것이기 때문이죠. 안드로이드가 여러 단점이 있지만 이미 모바일 생태계에서 입지가 탄탄하고 성능 개선을 위해 많은 개발자들이 노력하고 있고 성과도 나타나고 있죠.. 구글이 크롬을 인위적으로 띄워줘도 역전은 쉽지 않을 겁니다. 또한 안드로이드를 포기하진 않을것이구요..

      예전 비디오기기 시장에서 vhs와 베타 방식의 사례를 보더라도 알 수 있듯이 말입니다...
  9. 오래 전 글이지만 잘 보고 갑니다.

    모바일은 안드로이드를 2009년부터 개발하다가 아이폰 개발을 늦게 시작했지만 타이틀이 사실이긴 하죠..

    안드로이드 덕에 재미있게 보내고 있지만 부정하고 싶진 않네요 ㅋㅋ

    저는 2014년인가부터 순다 피차이 크롬 개발 담당하던 부사장이 구글 IO에 전면에 나선 걸 보고, 유니센터 계정분께서 말씀하신 것과 비슷한 걸 느껴오고 있었는데, 조금 다르게 생각해보니 크롬 OS랑 모바일 OS랑 별개로 계속 진행은 하겠지만 크롬이 구글의 주력사업으로 올라설거다라는 걸 상징적으로 보여준 게 아녔나라는 생각도 들고 ㅋㅋ 복잡하네요.

    잡설만 길었네요.

    여튼 IT 생태계는 돌고 도는 것 같다가 비슷하려나 모르겠네요 ㅎㅎ
    모두 즐프하세요~
    • 저야 안드로이드와 별로 관계 없는 일을 하기에 한발짝 떨어져 있으면서 보이는 대로 느끼는 대로 쓴 글이죠.. 사실 현 시점에서는 크롬OS는 등장만 했을 뿐 파급력은 잘 느껴지지 않습니다. 오히려 요즘은 MS의 모바일 시장에 대한 도전(?)이 강하게 느껴지는게 더 피부에 와닿기도 하구요.

      안드로이드의 속도 문제는... 자바 개발자들에겐 꽤나 예민한 문제 인것 같습니다. IOS개발하시는 분들은 오히려 덤덤한데 말이죠. ^^

      방문 감사합니다~ ^^

쉘 스크립트에서의 사칙연산과 문자열 자르기

Posted by taeho Tae-Ho
2013.10.08 10:00 운영체제

쉘에서 문자열 자르기를 설명하기 전에 쉘에서의 변수의 특징을 먼저 알아 보자.


일반적인 Java나 C와 같은 프로그래밍 언어에서는 변수의 선언과 타입(type)이 무척 중요하다. 선언하지 않고 사용하거나 잘못 참조하거나 잘못 연산하게 되면 엉뚱한 값이 출력되거나 컴파일 시 에러를 팍팍~뿌려댄다. 하지만 쉘스크립트에서는 변수는 선언하지 않으며 타입을 지정하지 않고 사용해도 된다. 


이따금씩 쉘 스크립트를 짜다보면 문자열과 숫자의 취급이 헷갈리곤 한다. C언어나  Java언어에서는 변수에 저장될 값이 숫자냐 문자냐를 무척 따져 형변환을 안해주게 되면 가차없이 컴파일 시 에러를 뿌려주는데 반해 쉘 스스크립트는 거침없이 알아서 연산을 한다.


아래 두 스크립트를 비교해보자.


a=10

b=10


let c=a+b


echo $a+$b=$c                                                                                  --> 출력결과 :  10+10=20


c=$a$b


echo $c                                                                                            --> 출력결과 : 1010


변수 a,b에 10이라는 숫자가 저장된 것으로 생각하겠지만 변수 a와 b는 숫자형으로도 사용이 가능하고 문자열로도 사용이 가능하다. 즉 산술연산식에 변수를 사용하면 숫자로 인식되어 계산되고 문자열 연산에 사용되면 문자열로 인식되어 합쳐지게 된다. 또한 연산의 결과를 받는 변수 c도 연산의 결과에 따라 숫자로 사용되기도 하고 문자로 사용되기도 한다.


아래의 스크립트도 앞의 스크립트와 같은 결과를 보여준다.


a="10"

b="10"


let c=a+b


echo $a+$b=$c                                                                          --> 출력결과 : 10+10=20


c=$a$b


echo $c                                                                                    --> 출력결과 : 1010


변수 a와 b의 초기화에 큰따옴표(")가 사용되어 언뜻 문자열로 사용될 것 같지만 연산식에 따라 숫자로도, 문자열로도 그때 그때 알아서(?) 쉘이 연산을 해준다.


쉘에서 변수의 특징을 이해하였다면 문자열 자르기로 넘어가자.


많은 스크립트 언어와 컴파일 언어에서는 문자열을 합치고 자르는 다양한 이해하기 쉬운 함수를 제공한다. 하지만 쉘에서는 조금 어렵다. 아니 어렵다기보다는 설명이 없이는 난해하다.


자릿수에 의한 문자열 자르기


${var:start:length} 

var : 문자열이 포함된 변수

start : 변수로부터 잘라낼 문자의 시작 번호 (0부터 시작됨)

length : start부터의 잘라낼 문자 갯수. length가 기술되지 않으면 끝까지.


예제 : 

IP="192.168.100.10"


echo "IP : "$IP


echo "12 to 2 : "${IP:12:2}


예제는 위의 하나로 충분하다고 본다.

IP라는 변수에 저장된 문자열 중에서 13번째 부터 2개의 문자열을 잘라내겠다는 의미다. 13번째인데 12가 쓰인 이유는 잘라내기 시작할 start는 0에서 부터 시작하기 때문이다. 일반적인 상식에서는 1이 숫자의 시작으로 생각하겠지만 프로그래밍에서 숫자의 시작은 0인 경우가 많다. 


패턴(구분자) 의한 문자열 자르기


 ${var%pattern}

문자열 변수 var의 끝에서 부터 pattern을 찾아 첫번째로 나타나는 패턴 문자열을 버린다.

 ${var%%pattern}

문자열 변수 var의 끝에서 부터 pattern을 찾아 마지막으로 나타나는 패턴 문자열을 버린다.

 ${var#pattern}

문자열 변수 var의 앞에서부터 pattern을 찾아 첫번째로 나타나는 패턴 문자열을 버린다.

 ${var##pattern}

문자열 변수 var의 앞에서부터 pattern을 찾아 마지막으로 나타나는 패턴 문자열을 버린다. 


음...이해가 쉽게 된다면 당신에게 경의를 표한다. -.- 내 머리는 나빠서인지 왜 이렇게 난해한 기호들을 나열하여 만들었는지 쉘이나 펄을 만든 이들에게 경외심마저 생긴다. 


${     } 는 중괄호{ } 안의 문자열을 처리를 수행하는 연산식이라는 것을 의미한다. 

var는 문자열이 저장된 변수다.

%와 #는 변수(var)에서 pattern을 찾기 시작하는 위치다. %는 문자열의 끝에서부터 pattern을 찾기 시작하며 #은 문자열의 처음부터 pattern을 찾기 시작한다.

pattern 은 잘라낼 패턴이다. 


가장 중요한 것은 pattern인데..... 여기가 좀 헷갈릴 수 있다. 예제를 보자.

[taeho@ncsd shell]$ cat str.sh

IP="192.168.100.10"

echo "IP : "$IP

echo ${IP%.*}


[taeho@ncsd shell]$ ./str.sh

IP : 192.168.100.10

192.168.100


가장 뒷부분을 잘라내서 버린다는 의미에서 패턴에 %를 사용했다.

다음과 같이 문자열을 자를 때 패턴으로 사용될 구분자.(마침표) 로 지정했다. 

와일드카드로 *을 사용했다. 즉 . 으로 시작하는 문자열 패턴이라는 의미에서 .* 인 것이다.

${IP%.*}


 192.168.100.10 에서 .으로 시작하는 문자열 패턴을 찾아 가장 마지막 패턴을 포함하는 문자들을 잘라내 버리는 것이다.


%를 두번쓰면 즉 %%를 사용하면 반대로 처음으로 .* 패턴이 나타나는 부분부터 끝까지를 버린다.

[taeho@ncsd shell]$ cat str.sh

IP="192.168.100.10"

echo "IP : "$IP

echo ${IP%%.*}

[taeho@ncsd shell]$ ./str.sh

IP : 192.168.100.10

192

[taeho@ncsd shell]$ 


pattern에서 %와 #의 차이는 패턴을 찾기 시작하는 문자열의 위치라고 앞에서 이야기했다.

일반적인 문자열이라면 %와%% #과 ##을 써서 동일한 결과를 뽑아낼 수 있지만 특이한 문자열 (예를 들면 맨 앞에 구분자로 사용할 특수문자(/,.| 등)가 있는 경우도 있고 없는 경우도 있을 경우...) 의 경우에는 구별하여 사용해야 한다.


정확한 의미를 이해하려면 여러가지 경우로 테스트해보기 바란다.


이전 포스트 보기 : [unix / linux] shell (쉘)을 이해하자.


신고
이 댓글을 비밀 댓글로

메모리 부하 테스트 프로그램 작성하기 (C언어, malloc()) - 가상메모리의 마술

Posted by taeho Tae-Ho
2013.09.28 15:33 운영체제

또 간만에 C 코딩할 일이 생겼다. 어쩌다 한번씩 코딩을 하다보니 실력이 늘지를 않는건 당연한 일이고 뭐하나 짜려면 시간이 꽤나 걸린다. 하지만 어쩌다 한번 코딩을 하니 재미가 있는건 사실이다. 


이번에 짤 프로그램은 서버의 메모리를 고갈시키는 프로그램이다. 메모리를 할당받았다가 릴리즈하는 작업을 반복하는 프로그램이다. 예를 들어 10개의 프로세스가 각 10 M Byte의 메모리를 100번씩 할당받았다 해제하는 것이다. 


즉 10 M Byte * 10 * 100 = 1 Tera Byte 를 할당받았다 해제했다를 반복하는 프로그램이다. 하지만 메모리의 할당과 해제 만으로는 서버에 거의 부하를 줄 수 없다는 것이 중요하다. 실제로 4G Byte의 메인메모리를 가진 서버에서 1 Tera Byte의 메모리를 할당 받는 프로그램을 실행해도 아무런 문제가 없었다. (CPU 사용율이 1%도 증가하지 않을 것이다. 또한 할당(malloc()) 만으로는 실제 메모리 액세스도 거의 발생하지 않는다. 즉, 부하가 없다.) 


이 포스트를 방문할 정도의 사람이라면 대부분 "가상 메모리 관리"라는  운영체제의 개념을 알고 있을 것이다. 


10개의 프로세스가 10 M Byte의 메모리를 각각 100번 씩 할당 받으면 운영체제는 가상메모리에 우선 할당하고(몇바이트 몇페이지만 할당했다고 표시만 하는 듯..) 프로세스 영역에는 할당된 가상메모리의 각각의 페이지를 관리하기 위한 오버헤드만 기록하고 만다. 그래서 실제로 아래 화면과 같이 ps aux 명령을 실행했을 때 표시되는 메모리 항목 2개의 값중 RSS (RSZ라고도 함) 실제 램에 상주하여 차지하고 있는 메모리의 크기)는 약 4K 정도의 오버헤드 정도만 malloc()에 의해 할당 받을 때 증가한다. 


10개의 프로세스가 10 M Byte를 100번 할당 받는 동안 메모리 사용율은 보통 다음 방법으로 모니터링할 수 있다.


첫번째가 ps aux 명령이다. 그 중에서도 VSZ와 RSS 두 항목이 프로세스별 메모리 사용량가 비율을 표시해준다. 하지만 실제로 해당 프로세스에 할당된 메모리의 양이 아니라 현재 실제로 사용중인 메모리의 양이라고 봐야한다.  즉, 할당 받은 메모리를 언제 사용할지 알 수 없는 것이다.  또한 할당 받은 메모리를 어떻게 사용하고 있는지도 알 길이 없다.



두번째는 vmstat다. vmstat는 ps aux와는 달리 프로세스별 메모리가 아닌 시스템 전체의 메모리 사용량을 보여준다. 



일반적으로 사용하는 세번째 방법이 바로 top 명령이다.

top은 시스템 전체의 메모리 사용율과 CPU사용율이 상위에 랭크되는 프로세스의 메모리 사용량을 모두 보여준다. 단, 여기서도 할당받은 메모리양이 아닌 할당 받은 뒤 실제 사용되는 메모리 사용량을 보여준다는 것을 꼭 기억해야 한다.



이 세가지 툴로 아무리 봐도 할당만 했을 때는크게 달라지는 점이 없다. 1 Tera의 무지막지한 메모리를 할당해달라고 하면 군소리 없이 할당해준다. 그리고 위의 top 화면에서 보이는 Mem의 Used 항목은 할당 받은 양에 비해 너무 작은 양이 증가한다. 


이렇게 많은 메모리를 할당 받았음에도 해당 프로세스의 메모리 사용량을 보면 할당받은 메모리 양보다 너무도 작게 보이는 이유는 할당만 받아놓고 실제 사용하지(접근하지) 않기 때문이다. 또한 실제 접근(사용)하지 않으면 메인메모리(RSS)나 가상메모리(VSZ)를 차지하지 않는다.


할당 받은 메모리를 실제 메모리에 로드하는 방법은 ?


방법은 간단하다. 실제 할당 받은 메모리에 4 K byte 영역마다 한번 씩 실제 액세스를 하는 것이다. 이렇게 4K(1개의 페이지) 마다 실제 액세스(값을 쓰기)하기 시작하면 top의 Mem항목에서 Used 항목의 값이 급격하게 증가하기 시작한다. (당연히 free는 줄어듦) 가상메모리에 할당만 해놨던 메모리의 각 페이지에 값이 저장되므로 실제 메모리에 페이지를 올리기 시작함.)


그리고 실제 메모리가 모두 차게되면 그때부터 Swap의 Used가 증가하기 시작한다. 즉 실제 메모리가 부족하므로 이미 값을 쓴 페이지를 swap 공간으로 내리고 내린만큼 메인메모리를 확보하여 계속 쓰기를 수행하는 것이다. 그리고 Swap의 Used가 Total과 같아지는 순간 더 이상 메인메모리를 확보할 수 없으므로 시스템은 멈춘다. (vi실행 등등 어떠한 작업도 불가능 하다.)


할당만 받았을 때는 실제 데이터가 없으므로 할당받은 것으로 표시만 해둠으로 해서 실 메모리는 4G Byte밖에 없지만 2의64제곱에 해당되는 번지수 만큼 메모리를 할당 받을 수 있지만 4 K마다 실 데이터를 Write 해서 해당 페이지를 실제 사용하면 운영체제는 해당 페이지를 실메모리(램)에 올려두거나 스왑공간에 유지해야 하는데 더 이상 스왑공간조차 모두 사용하게 되면 더 이상 메모리를 확보하지 못하는 상태가 되어 완전한 메모리 사용률 100%를 만들 수 있다.


이제 프로세스의 개수와 하나의 프로세스가 할당 받을 메모리의 양을 적절하게 조절하고 할당과 해제를 반복하면 메모리의 부하를 주는 아주 기본적인 프로그램이 완성된다. 


#include <sys/types.h>

#include <unistd.h>

#include <stdio.h>

#include <stdlib.h>


int main(void)

{

  pid_t pid, ppid;

  int intTmp, intTmp2;


  // 생성할 자식 프로세스의 개수

  int intChildsCt = 10;

  //자식프로세스의 PID저장할 목록(불필요)

  int intChilds[10];

  // 프로세스 당 메모리를 할당 받을 횟수

  int intMemAllocCt = 100;

  // 위의 횟수만큼 할당받은 메모리의 포인터를 저장할 포인터배열

  char *cpStr[100];

  // 한번 메모리 할당 받을 때의 메모리 크기(Byte)

  int intMemSize=10240000;


  // 한번 할당받은 메모리를 4K Byte 단위로 나누었을 때의 조각의 개수

  int intPageCt = intMemSize/4096;


  // 부모의 PID 획득

  ppid = getpid();


  pid = 1;


  // 자식 프로세스를 intChildsCT에서 지정한 만큼 반복하여 생성

  for (intTmp=0; intTmp < intChildsCt; intTmp++)

  {

     if (pid != 0) // 부모만 fork()가 실행되도록

     {

        // 자식을 생성(fork())하고 부모프로세스는 pid에 자식 pid를 받음. 자식에게는 0이 리턴됨.

        if ((pid=fork()) < 0)

        {

           printf("%d'th child process fork error\n", intTmp);

           return 2;

        }

        else if (pid != 0) // 부모는 pid를 배열에 저장.

        {

           intChilds[intTmp] = pid;

        }

     }

  }


  // for() 후 부모프로세스가 실행할 루틴.

  if ( pid != 0 )

  {

     printf ("==== ChildProcess List====\n");

     for (intTmp=0; intTmp < intChildsCt; intTmp++)

     {

        printf ("%d'st Child process pid : %d\n", intTmp, intChilds[intTmp]);

     }

  }


  // fork() 후 자식 프로세스가 실행할 루틴.

  if ( pid == 0 )

  {


     printf ("Child Routine...\n");


     // 생성된 자식은 intMemAllocCt에서 지장한 횟수만큼 반복하여 메모리 할당

     // 총 할당받는 메모리는 intChildsCt(자식의 개수) * intMemAlloct(자식 당 할당받을 횟수)  * intMemSize(1회에 할당받을 메모리) 만큼 임.

     for (intTmp2=0; intTmp2<intMemAllocCt; intTmp2++)

     {

        // 메모리를 할당하고 첫 주소를 cpStr[]에 저장. (포인터를 이해하려면 아래 라인을 완전하게 이해해야 함.)

        cpStr[intTmp2] = (char *)malloc(intMemSize);

        // 할당받은 메모리의 모든 바이트에 알파벳 K를 쓴다. (이 라인을 활성화하면 CPU 100% 침.

        // 단, 시스템이 금방 멈추지는 않지만 메모리가 부족하게 되면 멈출 수도 있음.

        //for (intTmp=0; intTmp<intMemSize; ++intTmp) *((char *)cpStr+intTmp)='K';

      

        printf("Child %d , Memory Allocate : %d\n", getpid(), intTmp2);

        sleep(1);


     }

     printf("ppid = %d, getpid = %d\n", ppid, getpid());

     //printf("%s\n", (char*)cpStr);


     // 10초간 대기

     sleep (10);


     // 각 자식 프로세스는 자신이 할당받은 메모리 횟수 만큼에 대해

     for (intTmp2=0; intTmp2<intMemAllocCt; intTmp2++)

     {

        할당받은 메모리를 4096바이트(page (4K))로 나눈 몫의 횟수만큼 (즉 할당받은 페이지의 수 만큼) 반복

        for (intTmp=1; intTmp<intPageCt; intTmp++)

        {

           //각 페이지의 첫번째 바이트에 'K'를 쓴다. 즉 할당받은 모든 페이지를 실제로 접근 발생시켜 실제 사용하는 페이지로 만든다.

 // 아래 라인의 의미를 이해하고 원하는 동작을 하도록 수정할 수 있다면 포인터의 기본을 이해하고 사용할 수 있는 수준이라 볼 수 있음.)

           *((char *)cpStr[intTmp2]+(4096*intTmp)) = 'K';

        }

     }

     // 할당받은 메모리의 모든 페이지를 한번씩 액세스하고 2초간 대기

     sleep (2);


     // 할당받은 메모리를 반환한다.

     for (intTmp2=0; intTmp2<intMemAllocCt; intTmp2++) {

        free(cpStr[intTmp2]);

        printf("pid=%d, %d is free...\n", getpid(), intTmp2);

     }

  }

  //프로그램 종료

  return 0;

}


이 소스를 기반으로 메모리에 다양한 부하를 주는 프로그램을 구미(?)에 맞게 만들면 되겠다.

신고
이 댓글을 비밀 댓글로