[Ubuntu] Python 버전 변경하는 방법

소개

Ubuntu에서 다수의 python 버전을 운영할 때, update-alternatives를 이용하면, 손쉽게 python 버전을 변경할 수 있습니다.

update-alternatives는 Debian 계열 시스템에서 다수의 패키지를 심볼릭 링크로 관리해 주는 명령어입니다. 해당 명령어는 python 뿐만 아니라, jdk와 같이 대부분의 패키지 버전을 관리하는데 사용할 수 있습니다.

현재 사용중인 Python 실행 위치 확인

which 명령어를 사용하면 현재 사용 중인 python의 실행 위치를 조회할 수 있습니다.

조회된 /usr/bin/python 파일을 ls 명령어로 조회해 보면, 심볼릭 링크이고 실제 python 바이너리가 다른 위치에 설치된 것을 확인할 수 있습니다.

이미 다른 버전의 python을 설치했다면 아래의 명령어로 설치된 python 버전들을 확인할 수 있습니다.

update-alternatives를 이용한 python 버전 변경

python 등록 여부 확인

update-alternatives --config python 명령어를 통해 update-alternatives에 등록된 python 버전이 있는지 확인할 수 있습니다.

python 버전 등록 및 변경

현재는 등록된 python 버전이 없으므로, update-alternatives --install [symbolic link path] python [real path] number 명령어를 이용하여 python 버전을 등록합니다.

update-alternatives --config python 명령어를 다시 입력하면 등록된 python 버전이 확인이 가능합니다.

숫자를 입력하여 원하는 버전의 python을 선택할 수 있습니다.

카테고리: Linux | 댓글 남기기

[Design Patterns] Model View Controller 패턴

MVC(Model-View-Controller)

MVC는 Model-View-Controller 의 약자입니다.

소프트웨어 설계 및 개발을 진행할때, 프로그램을 3가지 요소로 나누어 개발하는 ‘소프트웨어 디자인 패턴‘입니다.

MVC 패턴을 도입하면 도메인(비즈니스 로직) 영역과 UI 영역이 분리되므로 서로 영향을 주지 않고 유지보수가 가능합니다. MVC 패턴의 구조를 살펴보면서 각 컴포넌트가 무슨 역할을 수행하는지 알아보도록 하겠습니다.

MVC 패턴 개요

모델(Model)

DATA, 정보들의 가공을 책임지는 컴포넌트를 말합니다.

모델(Model)은 어플리케이션의 정보, 데이터를 나타냅니다. 데이타베이스, 처음의 정의하는 상수, 초기화 값, 변수 등을 뜻합니다. 비즈니스 로직을 처리한 후 모델의 변경사항을 컨트롤러와 뷰에 전달합니다.

모델은 다음과 같은 규칙을 가지고 있습니다.

  • 사용자가 편집하길 원하는 모든 데이터를 가지고 있어야 합니다.
  • 뷰나 컨트롤러에 대해서 어떤 정보도 알지 말아야 합니다.
  • 변경이 일어나면, 변경 통지에 대한 처리 방법을 구현해야만 합니다.

뷰(View)

사용자에게 보여지는 부분, 즉 유저 인터페이스(User interface)를 의미합니다.

MVC 패턴은 여러 개의 뷰(View)가 존재할 수 있으며, 모델에게 질의하여 데이터를 전달받습니다. 뷰는 받은 데이터를 화면에 표시해주는 역할을 가지고 있습니다. 모델에게 전달받은 데이터를 별도로 저장하지 않아야 합니다. 사용자가 화면에 표시된 내용을 변경하게 되면 모델에게 전달하여 모델을 변경해야 합니다.

뷰는 다음과 같은 규칙을 가지고 있습니다.

  • 모델이 가지고 있는 정보를 따로 저장해서는 안됩니다.
  • 모델이나 컨트롤러와 같이 다른 구성요소들을 몰라야 됩니다.
  • 변경이 일어나면 변경통지에 대한 처리방법을 구현해야만 합니다.

1.3. 컨트롤러(Controller)

모델(Model)과 뷰(View) 사이를 이어주는 브릿지(Bridge) 역할을 의미합니다.

모델이나 뷰는 서로의 존재를 모르고 있습니다. 변경 사항을 외부로 알리고 수신하는 방법만 있습니다. 컨트롤러(Controller)는 이를 중재하기 위해 모델과 뷰에 대해 알고 있어야 합니다. 모델이나 뷰로부터 변경 내용을 통지 받으면 이를 각 구성 요소에게 통지해야 합니다. 사용자가 어플리케이션을 조작하여 발생하는 변경 이벤트들을 처리하는 역할을 수행합니다.

컨트롤러는 다음과 같은 규칙을 가지고 있습니다.

  • 모델이나 뷰에 대해서 알고 있어야 합니다.
  • 모델이나 뷰의 변경을 모니터링 해야 합니다.
카테고리: Design Patterns | 댓글 남기기

Test Driven Development(테스트 주도 개발, TDD)

Test Driven Development(테스트 주도 개발, TDD) 란?

TDD는 Test Driven Development의 약자로, ‘테스트 주도 개발’이라고 합니다.

일반적인 개발 과정에서는 요구사항을 분석 후 설계를 마친 뒤에 프로덕션 코드(Production code)를 작성하는 합니다. 상황에 따라 프로덕션 코드를 작성한 후에 테스트 코드를 추가할 수도 있는데 이는 단위테스트이며, TDD와는 다릅니다.

TDD는 요구사항을 분석후에 테스트코드를 먼저 작성(Test First Development)하고 이후에 프로덕션 코드를 작성합니다. 이후에 프로덕션 코드와 테스트 코드를 리팩토링하는 과정을 반복하여 코드의 완성도를 높힙니다.

TDD = TFD(Test First Development) + Refactoring

Refactoring : 설계의 과정 중 하나, 기능의 변화 없이 클래스 구조, 메서드 분리를 하는 설계의 과정

TDD의 아이러니 중 하나는 테스트 기술이 아니라는 점이다. TDD는 분석 기술이며, 설계 기술이기도 하다.
Kent Beck, Test Driven Development by Example 중

TDD를 하는 이유

  • 디버깅 시간을 줄임
  • 동작하는 문서 역할
  • 코드 리팩토링에 대한 두려움을 줄여줌

TDD 싸이클

  • 실패하는 테스트를 구현한다.
  • 테스트가 성공하도록 프로덕션 코드를 구현한다.
  • 프로덕션 코드와 테스트 코드를 리팩토링 한다.

TDD 원칙

  • 원칙1 – 실패하는 단위 테스트를 작성할 때까지 프로덕션 코드를 작성하지 않는다.
  • 원칙2 – 컴파일은 실패하지 않으면서 실행이 실패하는 정도로만 단위 테스트를 작성한다.
  • 원칙3 – 현재 실패하는 테스트를 통과할 정도로만 실제 코드를 작성한다.
카테고리: TDD(Test-driven development) | 댓글 남기기

MPEG-2 TS(Transport Stream)

MPEG-2 시스템 개요

MPEG-2 시스템 표준

  • MPEG(Moving Picture Expert Group)-2 시스템은 비디오, 오디오 Elementary Stream(ES)을 저장 또는 전송하기 위하여 단일(single) 혹은 다중(Multiple) 스트림 멀티미디어 정보를 다중화(Multiplexing)하는 방식을 규정한 표준(ISO/IEC 13818-1)
  • MPEG-2 시스템에는 용도에 따라 Transport Stream(TS), Program Stream(PS)의 두 가지의 형태의 스트림을 제공

표 1 – Transport Stream과 Program Stream[5]

TS

(Transport Stream)

  • 전송용 스트림
  • 전송 에러가 존재하는 (error-prone) 전송 매체에 이용
  • 일정한 길이(188byte)의 packet으로 구성
  • 27MHz 단위의 PCR (Program Clock Reference)을 사용

PS

(Program Stream)

  • 저장용 스트림
  • 전송 에러가 없는 (error-free) 전송 매체에 이용
  • 가변 길이의 pack으로 구성
  • 27MHz 단위의 SCR (System Clock Reference)을 사용

PSI / SI / Section

서비스  정보는  수신기가  Transport Stream(TS)을  복호화 할  수  있게  하는 PSI(ISO/IEC IS MPEG-2 System 13818-1[1])와 선택된 프로그램 안내의 근간을 이루는 SI(DVB EN 300 468[2])를 포함한다.[3]

Section은 PES에 포함되는 오디오, 비디오 데이터를 제외한 나머지 정보들을 칭하며 하고 방송 수신 정보 PSI(Program Specific Information)와 방송 부가 정보 SI (Service Information) 및 기타 일반적인 데이터들이 여기에 해당한다. 실제로 Section은 구체적인 데이터인 Table의 일부분이고 수신부에서는 Packetized되서 전송되는 여러 개의 Section을 모아서 하나의 Table을 구성해야 유효한 정보를 얻을 수 있다. 실제로 각 Section Header의 신택스를 보면 section_number와 last_section_number와 같은 값이 있는데 해당 값을 통해 Packet을 재조립하여 하나의 Table을 완성하게 된다.

때때로 Table의 사이즈가 TS packet 사이즈보다 작은 경우가 있는데 이 경우에는 section_number와 last_section_number 값이 모두 0x00이 된다. Section Header 신택스 중에 table_id라는 값이 있는데, 수신부에서는 이 값을 이용하여 Packet에 어떤 Table 정보가 저장되어 있는지 알 수 있다.[7]

MPEG 다중화

그림 1 – MPEG 다중화[8]

그림 1는 MPEG 시스템의 다중화 과정을 통해 TS의 생성과정을 보여주고 있다. Encoder에 의해 코딩 된 비디오, 오디오 ES(Element Stream)는 가변적 크기로 잘라낸 후 헤더를 붙여 PES Packet이 된다. 이때 PES Packet의 크기는 고정되지 않고 가변적이며, PES Header에는 영상, 비디오의 싱크 정보(DTS, PTS) 등이 들어간다. 이 PES 패킷을 고정된 크기 184byte로 잘라내고 4byte Header를 붙여 TS Packet으로 변환한다. TS Packet은 최종적으로 하나의 TS 스트림으로 다중화 되게 된다.

PES / TS / PS

그림 2 – PES, TS, PS의 상관 관계

TS와 PS의 가장 큰 차이점은 기본단위(Packet, Pack)의 길이 이다. PS 스트림의 경우 저장용 스트림이기 때문에 저장매체에서 스트림을 읽는 경우 에러가 발생할 확률이 낮아 Pack의 길이가 가변적 이어도 문제가 되지 않는다. 그러나 전송용 스트림인 TS 스트림의 경우 전송 도중에 에러가 발생할 확률이 높기 때문에 Packet의 길이를 188byte로 고정하여 에러로 인한 데이터 손실을 최소화 한다.

TS 스트림은 Packet의 길이를 188byte로 고정시키기 위한 과정을 거치기 때문에 수신단에서 원본 데이터를 재조립하기 위한 부가적인 정보가 들어가게 된다. 이 정보들은 TS Header에 저장되며 수신단에서는 4byte인 TS Header를 분석하여 나머지 184byte Payload 데이터를 재조립한다.

그림 3 – ITU-T Rec.H.222.0 | ISE/IEC 13818 transport packet[1]

위 그림 3은 TS Packet의 구조를 보여주고 있다. 앞서 설명한 것처럼 TS Header는 기본적으로 4byte로 구성되고 필요에 따라 adaptation filed가 추가될 수 있다. TS Header의 구성을 살펴보도록 하겠다.

  • sync_byte (8 bit) : 0x47로 고정된 값을 갖고 TS Packet의 시작을 표시한다.
  • transport_error_indicator (1 bit) : 전송된 Packet에 에러가 있는지 없는지를 표시하며, ‘0’ 이면 에러가 없고 ‘1’이면 에러를 포함한다.
  • payload_unit_start_indicator (1 bit) : TS Packet의 경우 원본 데이터를 쪼개서 보내기 때문에 현재 packet이 포함하고 있는 데이터가 원본 데이터의 어느 부분을 포함하고 있는지를 알아야 수신단에서 원본 데이터를 재조립할 수 있다. 이 flag는 원본 데이터의 시작이 Packet에 있는지 없는지를 알려준다. 값이 ‘0’이면 해당 Packet에 원본 데이터의 중간 부분이 포함되어 있고 ‘1’이면 원본 데이터의 처음 부분이 포함되어 있다. 뒤에 나오는 continuity counter와 함께 사용된다.
  • transport_priority_indicator (1 bit) : TS Packet의 우선 순위를 표시하며, 값이 ‘0’인 Packet보다 ‘1’인 packet이 우선순위가 높다.
  • PID (13 bit) : Packet에 포함된 Payload의 데이터가 어떤 데이터인지를 알려주는 flag로 수신단에서는 이 값을 보고 필요한 데이터를 구분한다.

그림 4 – PID Table[1]

  • transport_scrambling_control(2 bit) : Payload의 scramble 유,무를 표시한다.

그림 5 – Scrambling control values[1]

  • adaptation_field_control(2 bit) : Adaptation field의 유,무를 표시한다.

그림 6 – Adaptation field control values[1]

  • continuity_counter(4 bit): 같은 PID를 갖는 Packet의 경우 1씩 증가하면서 전송되며 값이 15 (4 bit의 max값)가 넘어가면 다시 0으로 초기화 된다. Adaptation field만 전송되는 Packet의 경우에는 값이 증가하지 않는다.

ATM & TS Packet

그림 7 – ATM Packet으로 구성되는 TS Packet[4]

추가적으로 TS는 ATM(Asynchronous Transfer Mode) 방식으로 전송되는데 한 개의 회선을 여러 개의 채널로 분할해서 동시에 통신하는 다중화 방식 중 하나이다. 기존의 방송망이 ATM방식을 사용하므로 호환성을 위해서 디지털 방송 또한 ATM방식을 사용한다. ATM packet은 5byte의 Header와 1byte의 AAL(ATM Adaptation Layer) 그리고 47byte의 payload로 구성되어 총 53byte의 크기를 갖는다. TS Packet의 사이즈가 188byte인 이유는 ATM Packet에서 ATM Header 와 ALL을 제외한 payload 데이터 4개를 합쳐 구성되기 때문이다. (47byte x 4 = 188byte)

MPEG 동기화

그림 8 – MPEG 동기화[8]

MPEG 시스템에서는 영상 및 음성 미디어 간 Encoder 및 Decoder 간의 시각 기준의 일치를 위한 동기화가 필요하다.

STC

STC(System Timing Clock) : MPEG 시스템 송신 측에서 발생시키는 공통의 기준 클럭(27 Mhz)으로 수신 측에서는 이에 맞추어 STC 타이밍에 동기화 한다. 즉, 송수신부에서 동작의 기준이 되는 시스템 기준 클럭이다.

PCR / SCR

PCR, SCR은 송신 측에서 주기적으로 전송하고, 수신 측에서 이에 맞춰지는 기준 되는 시간 값이다. 송신 측에서 송신단 출력 순간의 STC 값을 표본화하여 주기적으로 전송하고, 수신측은 수신단 입력 순간에 수신단 STC를 보정하여 STC를 맞춘다.

  • PCR(Program Clock Reference) : MPEG-2 TS의 프로그램 시각 기준 값으로 프로그램 마다 기준 되는 시각 기준 값이다. 여러 프로그램들이 모여 하나의 TS를 구성하는 경우에는 각 프로그램 마다 PCR이 다른 시간 기준을 갖을 수 있으나, 가능하면 단일한 PCR을 갖는 것이 바람직하다. 인코더 시스템의 시간을 27Mhz의 System Clock으로 샘플링한 값으로 오디오, 비디오 재생 시 기준 시각으로 사용된다. 42 (33 + 9) bit 정확도를 가지고 있으며 MPEG-1과의 호환성을 위해 33 bit의 90Khz의 정확도를 가지는 PCR_base값과 27Mhz의 정확도를 가지는 9 bit의PCR_ext로 구성되어진다. TS Packet Adaptation Field에 위치하며, 0.1초 이내 최소 1회 이상 전송된다.
  • SCR(System Clock Reference) : MPEG-1 PS의 시스템 시각 기준 값이다. PS는 단일 프로그램으로 이루어지므로 SCR 값을 항상 하나이다. PS의 Pack Header의 SCR 필드를 통해 전송되며, 0.7초 이내 최소 1회 이상 전송된다.

DTS / PTS

기준 클럭 시간 값에 따라, 오디오,비디오 ES 각각에 대해 PTS/DTS 타임스탬프를 사용한다. 디코딩을 위한 시각이 DTS(Decoding Time Stamp)이며, 재생을 위한 시각이 PTS(Presentation Time Stamp) 이다.

  • DTS(Decoding Time Stamp) : 수신된 오디오, 비디오 정보가 디코딩 되어져야 하는 시각을 나타내며 PES Packet Header에 위치한다.
  • PTS(Presentation Time Stamp) : 오디오나 비디오가 실제로 재생 되어져야 하는 시각을 나타내며, PES Packet Header에 위치한다.

디지털 방송 Channel Search

디지털 방송 수신과정

그림 9 – 위성방송 데이터 수신 구조

그림 3은 하나의 위성에서 송신하고 있는 정보들의 구조를 보여주고 있다. 여기서는 1개의 위성에3개의 Transponder(TP)가 존재하고 있다. TP는 방송국 단위로 생각할 수 있다. 우리나라 지상파 방송국(SBS, KBS, MBC)의 경우 각 방송국마다 보통 한 개의 서비스(=채널)만을 제공하고 있지만 그림 1의 TP2는 세 개의 서비스를 제공하고 있다. 특정 방송국의 경우 다수의 서비스를 하나로 묶어 부케단위로 제공하기도 한다. 서비스 정보를 확인하기 위해서는 위성에서 데이터를 송신할 때 사용하는 주파수 정보 등을 알고 있어야 한다. 구체적으로 Frequency, Symbol rate, Polarization(Horizontal, Vertical) 등의 정보가 있어야 TP에 락킹하여 방송 신호를 수신할 수 있다. 수신기(셋탑박스)에서는 기본적으로 위성 정보를 저장하고 있지만 없는 경우에는 원하는 위성 정보(www.lyngsat.com)를 확인 후 수동으로 방송 신호를 수신할 수 있다. 일반적으로 셋탑박스에서는 이 과정을 최초 한번만 수행하면 데이터베이스에 저장하고 그 이후에는 이 과정을 수행하지 않는다. 물론 방송국 혹은 위성에서 변경사항이 발생하면 그 정보를 새로 수신하여 반영하여야 한다.

Channel Search 방법

Tuner Locking

그림 10 – 위성방송 서비스 Channel Search 과정[7]

셋탑박스는 TP 정보를 통해 락킹을 시도하게 되는데 TP정보를 얻는 방법은 크게 2가지다. 첫째, TP 정보를 OP에게 입수하여 미리 플래시 메모리에 저장하는 방법이 있으며, 둘째, NIT 테이블을 파싱하여 테이블 내의 delivery system descriptor를 읽는 방법이다.

TP가 락킹된 후 튜너의 DeMod와 DeMux를 거치게 되면 TS 스트림이 출력되고 SI 데이터 파싱을 위해 sync_byte(0x47)을 찾는다. sync_byte를 찾으면 188byte 이후의 byte를 조회하여 sync_byte인지 확인하고 이 과정을 3회 연속 성공하면 정상적인 TS 스트림으로 보고 최종 락킹하게 된다.

TP 락킹이 성공적으로 완료되면 PAT를 파싱하게 되고 PAT 파싱을 통해 PMT의 PID와 개수 등을 알게된다. PAT 파싱을 완료하면 PMT 테이블의 개수만큼 PMT를 파싱하게 되고 PMT 파싱을 통해 해당 서비스의 Video PID, Audio PID 등을 파악한다. 마지막으로 SDT를 파싱하여 각 서비스별 채널명, 속성정보 등을 파악하게 된다.

PAT 파싱

튜너가 특정 TP를 락킹하여 TS 스트림을 출력하게 되면 가장 먼저 PID가 0x000인 PAT 테이블을 파싱 하게 된다. PAT 테이블은 서비스(=채널)들의 정보를 담고 PMT 테이블의 PID를 얻어낸다. 하나의 TP에는 PAT 테이블이 한 개로 유일하며, 최소 0.7초 마다 한번씩 발생하는 것으로 알려져 있다.

그림 11 – Program association section[1]

PMT 파싱

PAT 파싱에서 얻어낸 PMT PID에 따라 PMT 테이블을 파싱한다. PMT는 하나의 TP에 서비스의 개수 즉 채널 개수만큼 있으며 한 TP에 4개의 방송이 있다면 PMT 테이블도 4개가 있다. PMT 테이블은 Video PID, Audio PID, CAT PID 등의 정보를 담고 있다. 이렇게 얻어낸 서비스별 PID의 리스트를 셋톱박스에 저장해두고 이후 사용자가 채널을 변경하면 해당 채널에 맞춰 화면에 디스플레이 하고 오디오를 구동하는데 쓰이게 된다.

예를 들어 BBC HD라는 방송이 있을 때 Video PID가 0x1001, Audio PID가 0x1002라고 가정하면, 사용자가 BBC HD라는 방송으로 채널을 돌리면 화면에는 PID 0x1001을 갖는 비디오 스트림을 뿌려주고 0x1002라는 사운드 스트림을 틀어주면 되는 것이다. 방송이 바뀔 때 마다 스트림의 PMT 테이블을 찾고 Video PID, Audio PID 등을 얻어 낸다면 채널 변경시간(Zapping Time)이 오래 걸리기 때문에 보통 서비스(=채널) 서치 과정에서 이러한 정보를 미리 셋톱박스의 데이터베이스에 저장해 놓는다.

그림 12 – TS program map section[1]

SDT 파싱

SDT 파싱을 통해 서비스명을 얻어내고 채널과 관련된 속성 정보를 얻어내어 마찬가지로 셋톱박스의 데이터베이스에 저장해 놓는다. 즉 방송의 이름을 알아내고 관련된 정보를 알려주는 것이 SDT의 역할이다.

그림 13 – Service description section[2]

Channel Search Pseudo 코드 정리[7]

References

  • [1] ISO/IEC 13818-1
  • [2] ESTI, EN 300 468
  • [3] 한국정보통신기술협회, TTAS.KO-07.0008/R1, 2000
  • [4] 유시룡, 장규환, 이병욱, 김종일, 정해묵, MPEG 시스템, 브레인코레아
  • [5] 강성곤, MPEG-2 System, 휴맥스, 2008
  • [6] 김규현, MPEG-2 ES/PES/TS/PSI, Media Lab of Kyung-Hee UNIV
  • [7] Google, “디지털 방송 채널 서치”, http://blog.naver.com/windheim/90048572443, (2009. 6. 8)
  • [8] Google, “MPEG 시스템”, http://www.ktword.co.kr/test/view/view.php?nav=2&no=3682&sh=MPEG, (2018. 11. 05)
카테고리: MPEG | 댓글 남기기

[C] 댕글링 포인터(Dangling Pointer)

댕글링 포인터 정의

  • 포인터가 여전히 해제된 메모리 영역을 가르키고 있다면, 이러한 포인터를 댕글링 포인터(Dangling Pointers)라고 부른다. ⇒ 댕글링 포인터가 가리키는 메모리는 유효하지 않다.
  • 댕글링 포인터는 종종 너무 빠른 해제(premature free)라고 불린다.

댕글링 포인터 문제점

  • 메모리 접근 시 예측 불가능한 동작
  • 메모리 접근 불가 시 세그멘테이션 오류(Segmentation fault) 발생
  • 잠재적인 보안 위험

댕글링 포인터 발생 원인

  • 메모리 해제 후, 해제된 메모리에 접근하는 경우
  • 함수 호출에서 자동 변수를 가리키는 포인터를 반환
카테고리: C, Programming | 댓글 남기기

[C] 메모리 누수(Memory Leak)

메모리 누수 정의

메모리 누수는 할당된 메모리가 더는 사용되지 않지만, 해제되지 않을 때 발생한다. 이를 테면 다음과 같은 상황에서 발생한다.

  • 메모리의 주소를 잃어버린 경우
  • free 함수가 호출되어야 하는 상황에 호출되지 않은 경우

메모리 누수의 예

  • 메모리 누수가 누적되면 힙 관리자가 사용할 수 있는 메모리 양이 감소하게 된다.
  • 메모리 누수가 반복되면, 추가적인 메모리가 필요할 때 malloc 함수가 OOM(Out of Memory) 오류를 발생시키며 추가적인 메모리를 할당하지 못해 프로그램이 종료된다.

아래의 코드는 메모리 누수를 발생시키는 코드의 예이다. 변수 chunk는 힙으로 부터 메모리를 할당받지만, 다른 메모리가 할당 되기전에 해제되지 않는다. 이 코드는 결국 OOM 오류를 발생시키고 비정상 종료된다.

메모리 주소 손실

  • pi 포인터는 해제되지 않은 상태에서 새로운 메모리 주소가 재할당된다.
  • pi 변수에 두 번째 메모리 주소가 할당될 때, 첫 번째 메모리의 주소는 손실된다.

아래의 그림에서 메모리 주소 Ox0E는 여전히 해제되지 않은 상태이며 프로그램 어디에서도 이 주소를 알지 못한다.

메모리 주소 손실

 
  • 아래의 예제 코드는 name 변수를 루프의 반복마다 1씩 증가시킨다.
  • 루프의 마지막에 name 변수는 문자열의 NUL 종료 문자를 가리킨다. ⇒ 할당된 메모리의 시작 주소를 잃어버림.

동적으로 할당된 메모리 주소 손실

 

숨겨진 메모리 누수

숨겨진 메모리 누수는 보통 프로그래머의 부주의에 때문에 발생한다.

  • 대표적인 예로는 struct 키워드를 사용하여 생성한 구조체를 내부에 멤버 변수로 포인터 변수가 존재하는 경우이다.
  • 만약 구조체 내부에 동적으로 생성된 메모리의 포인터를 포함하고 있다면, 이 포인터는 구조체를 해제하기 전에 반드시 해제되어야 한다.
카테고리: C, Programming | 댓글 남기기

[C] 포인터와 메모리

C 프로그램에서의 메모리

컴파일된 C 프로그램은 다음 세 종류의 메모리를 사용한다.

정적(Static)/전역(Global)

  • 정적(Static)/전역(Global)으로 선언된 변수들은 정적/전역 메모리에 할당된다.
  • 정적/전역 변수들은 프로그램이 시작될 때 할당되며, 프로그램이 종료될 때까지 메모리 공간에 남아 있다.
  • 전역 변수는 파일 전체가 접근 범위(scope)이며, 정적 변수의 접근 범위는 해당 변수를 선언한 함수로 제한된다.

자동(Automatic)/지역(Local)

  • 지역 변수(종종 Automatic 으로 언급)는 함수 안에서 선언되고 함수가 호출될 때 생성된다.
  • 지역 변수의 접근 범위는 선언된 함수로 제한되며, 함수가 호출되는 동안에만 메모리에 존재한다.

동적(Dynamic)

  • 동적 메모리는 힙(Heap) 메모리 영역에 할당되고 필요한 경우 해제된다.
  • 포인터를 사용하여 할당된 메모리 영역을 참조하며, 포인터에 의해 접근이 제한된다.
  • 메모리를 해제하지 않는 한 메모리에 계속 존재한다.

접근 범위(scope)와 수명(Lifetime)

메모리의 종류 접근 범위 수명
전역 전체 파일 프로그램 실행 동안 유지
정적 선언된 함수 프로그램 실행 동안 유지
로컬(자동) 선언된 함수 함수 실행 동안 유지
동적 참조하는 포인터 메모리 해제 전까지 유지

포인터 변수는 다른 변수 및 객체(Object) 또는 함수의 메모리상 주소를 포함하고 있다. 여기서 객체란, malloc 함수 같은 메모리 할당 함수를 사용하여 할당된 메모리를 말한다.

포인터는 가르키는 대상에 따라 특정 타입을 가지도록 선언된다. (정수, 문자, 문자열 혹은 구조체 등)

그러나 포인터 자체는 포인터 자체가 가르키는 데이터 타입의 속성을 가지지 않는다. 포인터는 단지 주소만을 가지고 있다.

포인터의 용도

  • 빠르고 효율적인 코드 작성
  • 다양한 문제에 대한 효과적인 해결 방법 제공
  • 동적 메모리 할당 지원
  • 작고 간결한 표현의 사용
  • 큰 오버헤드 없이 데이터 구조를 포인터로 전달
  • 함수의 매개변수로 전달된 데이터 보호

포인터 사용 시 주의점

  • 배열이나 데이터 구조의 경계를 넘는 접근
  • 소멸한 자동/로컬 변수의 참조
  • 힐당 해제된 힙 메모리의 참조
  • 아직 할당되지 않은 포인터에 대한 역참조
 

표준 문서에서의 포인터 동작 정의

C99(ISO/IEC 9899:TC3)

구현 방법에 따라 정의된 행동(Implementation-defined behavior)

  • 동작에 대한 문서화된 구현을 제공한다. ⇒ 정수에 대한 오른쪽 시프트 연산에서 상위 비트의 확장 방법

명시되지 않은 행동(Unspecified behavior)

  • 동작에 대한 구현을 제공하지만 문서화하지는 않는다. ⇒ malloc 함수에 인자를 0으로 주고, 실행할 때 메모리가 얼마나 할당되는가에 대한 문제
  • 명시되지 않은 행동의 목록 : CERT Secure Coding Appendix DD

정의되지 않은 행동(Undefined behavior)

  • 포인터의 동작에 대한 어떤한 것도 강요하지 않으므로 어떠한 동작도 발생할 수 있다. ⇒ free 함수에 의해 해제된 포인터의 값
  • 정의되지 않은 행동의 목록 : CERT Secure Coding Appendix CC

 

카테고리: C, Programming | 댓글 남기기

[Android] Kotlin을 활용한 android.os.properties 접근

해당 글에서 언급하는 프로퍼티는 안드로이드 시스템에서 관리되는android.os.SystemProperties를 의미합니다. (APK 내부에서 관리되는 System.getProperty, System.setProperty 와는 다릅니다.)

안드로이드 시스템에 시스템 속성(System Property)를 추가하거나 API로 구현하는 방법에 대해서는 아래의 안드로이드 문서에 잘 정리되어 있습니다.

시스템 속성 추가
시스템 속성을 API로 구현

다만, 위에 소개된 안드로이드 문서대로 ‘시스템 속성(System Property)’를 추가하기 위해서는 아래와 같은 사항이 동반되어야 합니다.

  • 플랫폼 빌드시 같이 빌드되는 시스템 app일 경우 android.os.SystemProperties 사용 가능
  • 플랫폼 빌드시 사용되는 key를 가지고 app을 signing 하여 app을 빌드하면 사용가능

만일, R&R에 따라 플랫폼 빌드 업무(패키징)와 app을 개발하는 업무가 분리되는 경우에 app 개발단에서 위와 같이 시스템 속성을 추가하는 것이 어렵습니다.

그런데 reflection을 이용하면 app 단에서도 안드로이드 시스템 프로퍼티를 get/set 할수 있습니다. 아래에 Kotlin 예제 코드를 첨부합니다.

카테고리: Android | 댓글 남기기

[Android] ADB를 이용한 파일 복사(adb pull / push)

개요

안드로이드 플랫폼에서 개발시에  MTP 를 통해 파일을 주고 받기 어려운 경우가 있습니다. 이런 경우 ADB pull / push 명령어를 통해 호스트 장치와 안드로이드 장치간 파일을 공유할 수 있습니다.

ADB 디버깅 설정

ADB를 사용하기 위해서는 안드로이드 장치에서 USB 디버깅 옵션이 활성화 되어 있어야 합니다.

  • 설정 > 기기 환경설정 > 정보 > 빌드 메뉴를 7번 이상 선택하면 개발자 옵션이 활성화 됩니다.
  • 개발자 옵션이 활성화되면 설정 > 기기 환경설정 > 개발자 옵션 > USB 디버깅 옵션을 활성화 합니다.

ADB push / pull 명령어 사용법

ADB push : 호스트(PC)에서 안드로이드 기기로 파일 복사

ADB pull : 안드로이드 기기에서 호스트(PC)로 파일 복사

 

카테고리: Android | 댓글 남기기

[Docker] Volume에 대한 이해와 활용

이 글에서는 Docker Volume에 대해서 설명하고 상황에 따라 Volume을 활용해 데이터를 관리하는 방법에 대해서 기술합니다.

개요

가장 기본적으로 Docker Container가 생성되면 Writable Layer에 데이터를 저장할 수 있습니다. 그런데 이 방법에는 몇가지 문제가 있습니다.

  • Container가 삭제되면 Container 내부에 데이터도 같이 삭제가 됩니다.
  • 현재 Container에 저장된 데이터를 다른 Container 혹은 프로세스와 공유하기 어렵습니다.
  • Container가 Writable Layer에 Data를 저장하기 위해서는 파일 시스템을 관리하는 스토리지 드라이버가 필요합니다. 그렇기 때문에 기존 호스트 파일 시스템 대비 데이터 읽기 쓰기 속도 성능이 떨어집니다.

Reference : About storage drivers

Docker 에서는 데이터 관리를 위해 volume, bind mount, tmpfs 의 총 3가지 방법을 제공하며, 이는 각각의 장점과 단점이 있기 때문에 상황에 맞게 활용해야 합니다.

도커에서 데이터를 관리하는 3가지 방법

아래 그림은 도커에서 데이터를 관리하는 방법에 대한 다이어그램입니다.

Reference : Use volumes

먼저 bind mount 를 살펴보면 Container 가 호스트 파일 시스템에 직접 접근하고 있습니다. 컨테이너에서 마운트한 경로의 호스트 파일과 디렉토리가 컨테이너 내부에 동일하게 표시되기 때문에 가장 간편한 방법일 수 있습니다. 하지만 호스트 파일 시스템 구조에 의존하기 때문에 호스트 파일 시스템과 컨테이너 내부의 파일 시스템 간의 파일/디렉토리 구조가 다른 경우 문제가 발생할 수 있습니다. (이에 대한 개인적인 경험은 뒤에서 자세하게 다룰 예정입니다.)

두번째로 volume 을 살펴보면 호스트 파일 시스템 내부에 Docker area 를 참조하고 있습니다. volume은 호스트 파일 시스템 내부에 Docker 에서 직접 관리하는 영역을 생성하여 사용하게 됩니다. volume은 Docker에 의해서 관리되기 때문에 호스트 파일 시스템과 완전 분리된다는 점이 있긴 하지만 사용방법은 bind mount 와 유사합니다.

마지막으로 tmpfs 는 ramfs와 비슷하게 메모리에 마운트를 하는 방법입니다. 이는 여러가지로 활용될 수 있습니다. 데이터베이스 경로를 tmpfs로 마운트 시켜 In-memory 데이터베이스 형태로 사용하면 디스크에 직접 접근하는 방식보다 빠른 성능을 보장 받을 수 있습니다. 또한, Read-only 옵션을 추가하는 경우 외부의 접근으로 부터 컨테이너 내부를 Immutable 한 상태로 유지할 수 있습니다.

실제 사용예제

bind mount

volume

tmpfs

졸리당… 사용 방법은 내일 정리 하는 걸로다가…

카테고리: Docker | 댓글 남기기