바이너리의 단점

마지막 업데이트: 2022년 4월 20일 | 0개 댓글
  • 네이버 블로그 공유하기
  • 네이버 밴드에 공유하기
  • 페이스북 공유하기
  • 트위터 공유하기
  • 카카오스토리 공유하기
ash84

[C#] .NET 어셈블리1

COM 바이너리의 문제점 – 배포의 문제 : 시스템 레지스터에 등록해야 하는 번거로움이 존재한다. : .NET – 배포하고자 하는 어셈블리를 응용프로그램이 있는 위치에 복사하면 된다. – 버전관리의 문제 : 이전 버전을 사용하는 여러 프로그램이 새로 배포한 새 버전에 의해서 실행상의 문제가 발생할수 있다. 버전관리가 매우 어렵다. : .NET – 동일한 바이너리(어셈블리)의 여러버전이 한 머신안에 설치되어 사용되어 질수 있다.

.NET 바이너리(어셈블리)의 5 구성요소 – 표준 WINDOWS 파일헤더 : 해당 모듈이 윈도우 운영체제에 의해서 사용될수 있다는 것을 나타내는데 이용 – 파일을 관리 모듈로 표시하는 CLR 헤어 : CLR에 의해서 로드될수 있는 모든 .NET 파일들이 지원해야 하는 정보의 블록] : CLR이 해당 관리파일의 구조 이해를 위해서 필요한 플래그(flag)들이 있다.( – CIL 코드 : 플랫폼과 CPU에 독립적인 CIL이 있어야 함. : 나중에 JIT 컴파일러에 의해서 플랫폼과 CPU에 맞게 컴파일 된다. – 형식 메타 데이터 : 어셈블리 내의 형식에 대한 설명 + 어셈블리에서 참조하는 외부형식에 대한 설명 – 어셈블리 메니 페스트(manifest) : 어셈블리 이름(문자열) : 버전 번호(주번호, 부번호, 빌드번호, 바이너리의 단점 수정번호) : 어셈 블리에 있는 모든 모듈 목록 : 참조된 어셈블리들에 대한 정보 단일 파일 어셈블리 – 하나의 모듈 (논리적 어셈블리와 물리적 바이너리사이에 1:1 관계) 다중 파일 어셈블리 – Mainfest가 다른 관련된 파일들을 참조하는 형식 물리적 어셈블리 – 사용자 지정형식과 리소들이 포함된 파일 논리적 어셈블리 – 현재 응용 프로그램에서 이용할수 있는 public 형식의 버전관리가 되는 집합체

이점 – 어셈블리는 코드의 재사용성을 높여준다. – 어셈블리는 형식의 경계를 만든다. – 어셈블리는 버전관리가 바이너리의 단점 되고 자기 설명적 개체이다. : 버전식별자를 통해서 정확한 어셈블리의 로드를 만든다. – 어셈블리는 보안 컨텍스트를 정의한다. : 보안의 수위는 어셈블리 바이너리의 단점 수준에서 정의된다. : 정의된 보안제약사항은 메니페스트에 명시적으로 나열된다. – 어셈블리는 병렬적 실행을 가능하게 한다. : 동일한 어셈블리의 여러 버전을 하나의 머신에 설치하고 로드가 가능.

ash84

ash84

파이썬을 좋아하는 개발자이며, 두 아이의 아빠입니다. 최근에 Infra, Devops 에 관심을 가지고 있습니다. 🤩

프로그래밍과 수학

C#을 공부한지도 한 2개월 정도 되어 가는 것 같다. 문법적인 부분에 대해서 익히는건, 오래 걸리지 않았다. (원래, C/C++,JAVA를 해봐서). 대신 오래 걸렸던 것은 C#의 여러기능을 잘 이용해서 프로그래밍 하는 것이었다. 자꾸만 주먹구구식의 C++하던 식으로 해서 그런지, 적절한 Class Member의 사용이 쉽지 않았다. 이제는 좀 익숙하다. 처음에 int형을 string 형으로 변환하려고 책을 찾아 보던것도 이제는 자연스럽게 Tostring()을쓰게 되고. 많이 좀익숙해진 느낌이다. 그래도 나는 아직 걸음마를 뗀 아기일뿐이다. 닷넷 개발자로서 말이다.

ash84

[C#] System.Collections.Stack

ash84

바이너리의 단점

여기서 잠시 유의할 점은, 느리다는 내용은 대부분 C/C++, Pascal, Fortran 같은 네이티브 바이너리 코드를 만드는 언어와 비교했을 때의 이야기입니다. 자바가 C/C++ 보다 2~3배 느리다고 하지만 다른 고수준 언어들에 비해서는 그리 떨어지지 않습니다. 1.4 버전에서 JIT 컴파일 지원이 돼서 많이 빨라졌습니다. 특히 인터프리터/스크립트 언어는 구조적으로 자바에 비해서도 훨씬 느립니다. 예를 들어 요즘 인기 있는 Python은 C보다 수십 배 느리고, 그나마 빠르다고 하는 JavaScript도 자바에 비해서 2배 정도 느립니다.

또한 속도 관련 문제는 하드웨어의 성능이 점점 좋아지고 메모리 가격이 떨어지면서 희석되고 있습니다. 처음 자바가 나왔을 때인 1995년만 하더라도, 느린 성능 때문에 그다지 많이 쓰이지는 않을 것이라고 예상했지만 현재 자바가 가장 많이 사용되는 곳 중 하나는 안정성과 일정 수준 이상의 성능이 요구되는 서버입니다. 자바가 네이티브 코드보다 느리지만 대부분의 상황에서는 큰 문제가 되지 않습니다.

1-1. JVM 로딩 속도 문제

자바의 심각한 단점 중 하나는, 실행하는 과정에서 JVM(Java Virtual Machine)이 반드시 완벽하게 로딩되어야 하기 때문에 프로그램의 초기 시작 시간이 완전한 이진 코드로 컴파일된 프로그램을 실행하는 것에 비해 오래 걸리는 것입니다. 단적인 예로, 아무것도 안 하고 콘솔 화면에 달랑 "Hello, World!"라고 찍기만 하는 프로그램이 실행되는 데에도 thread가 10개쯤 뜨는데, 특히 그 프로그램에 AWT, Swing, SQL 같이 불필요한 기능을 끌어들이는 것은 매우 심각한 문제입니다. 이 문제는 런타임 자체가 아직 모듈화 되지 않았다는 점에서 기인합니다.

하지만 요즘 같은 고사양 컴퓨터에서는 아주 많은 라이브러리를 끌어오는 것이 아니라면 체감상 차이는 바이너리의 단점 크게 나지 않습니다. 또한 Java 9부터는 드디어 런타임 라이브러리를 모듈화하고 있으므로, 필요한 모듈만 끌어서 프로그램을 짤 수 있습니다.

1-2. 가상 머신 바이트코드 실행 속도 문제

C/C++, Pascal, Fortran과 같은 언어와 달리, 자바는 바이트코드로 된 프로그램을 실행하기 바이너리의 단점 위해 운영체제와 프로그램 사이에 JVM이라는 두꺼운 계층이 하나 더 자리 잡게 됩니다. 그리고 바이트코드는 실시간으로 각 타깃 바이너리의 단점 플랫폼용 기계어로 번역되어 실행됩니다. 이로 인해 네이티브 바이너리 코드를 출력하는 언어와 비교하여 실행 속도와 성능에 일정 부분 손실이 발생할 수밖에 없습니다. AWT, Swing 같은 GUI 라이브러리를 사용할 때도 심각하게 느린 것을 체감할 수 있습니다. 이런 문제점을 썬 마이크로시스템즈도 곧 깨달았고, 최초 발표에서 2년 후인 1998년부터 JIT 컴파일러를 JVM에 내장하여 성능이 상당 부분 개선되었습니다. 하지만, 그만큼 메모리가 뒷받침해줘야 합니다. 현재는 보통 같은 기능/알고리즘을 실행하는 데 C++ 보다 2~3배 정도의 시간이 더 필요하다고 알려져 있습니다. 이 부분은 꽤 초기부터 지속적으로 개선되어 왔기 때문에 현재 실행 속도 자체에 대한 이슈는 예전에 비해 많이 줄어든 편이긴 합니다.

이 문제는 Java 9에서 '선행 컴파일'이라는 이름으로 개선될 예정입니다. JIT 컴파일로 실행과 동시에 컴파일을 하는 게 아니라 기존의 정적 컴파일처럼 바이트코드를 미리 기계어로 번역하면, 컴파일 속도는 다소 느려지지만 실행 속도는 빨라지게 됩니다. 물론 컴파일 한 번으로 여러 플랫폼에서 동일하게 실행시키는 건 불가능해집니다.

1-3. 가비지 컬렉션에 의한 실행 지연 문제

가비지 컬렉션에 의한 메모리 프리징 현상이 초반부터 지속적으로 자바를 괴롭혔습니다. 멀쩡하게 동작해야 할 프로그램이 순간적으로 뚝 뚝 끊기는 듯한 현상이 발생하는 것이죠. 오늘날 자바의 문제는 바이트코드 변환으로 인한 속도 저하보다 이 가비지 컬렉션의 영향이 더 크다고 할 수 있습니다. 이러한 문제점은 가비지 컬렉션을 지원하는 다른 프로그래밍 언어들도 마찬가지이긴 하지만 실행 속도와 함께 자바 초기부터 꾸준히 문제로 꼽혀온 것으로, 버전이 올라갈 때마다 다양하게 개선되어 왔습니다.

Java 8부터는 메모리 누수를 일으키던 메서드 영역의 PermGen Area를 제거하여 static 인스턴스와 리터럴 문자열도 GC의 대상이 되도록 바뀌었으며, 클래스, 메서드, 배열의 메타 정보는 동적 리사이징이 가능한 Metaspace로 이동시켜 시스템 힙 영역에 저장됩니다. 덕분에 JVM 힙 영역의 공간이 늘어나고 PermGen Area를 스캔/삭제할 필요가 없어져 GC의 성능이 대폭 향상되었습니다.

바이너리의 단점

이진탐색트리는 이름에서 알 수 있듯이 자식노드를 최대 2개까지만 가지는 이진트리의 특성을 가지고 있으며 다음과 같은 조건을 만족한다.

1. 어떤 노드 V를 기준으로 왼쪽 서브트리의 모든 키값 은 V보다 작아야 한다.

2. 어떤 노드 V를 기준으로 오른쪽 서브트리의 모든 키값은 V보다 커야 한다.

3. 각 노드의 키값은 유일해야 한다.

아래 트리는 이진탐색트리의 모든 조건을 만족한다.

이진탐색트리를 중위순회로 방문하면 오름차순으로 정렬된 값을 얻을 수 있다.

이진탐색트리는 그 이름에 '탐색'이 있듯 탐색이 효율적이다.

위의 이진탐색트리에서 8을 탐색해보자

우선 루트노드 6을 8과 비교했을 때 8은 6의 오른쪽 서브트리에 존재할 것이기 때문에 왼쪽 바이너리의 단점 서브트리는 탐색할 필요가 없다.

다음으로 오른쪽 서브트리의 루트노드인 9를 8과 비교하면 8은 9보다 작기 때문에 9의 왼쪽 서브트리로 내려간다.

9의 왼쪽 서브트리에 우리가 찾고자 하는 8을 찾았다.

만약 위의 이진탐색트리에서 3을 찾고자 한다면

6, 2, 4를 거쳐 3이 존재하지 않는다는 것을 알 수 있다.

즉 이진탐색트리에서 탐색연산의 시간복잡도는 트리의 높이인 O(h)가 된다.

최악의 경우 Leaf노드까지 탐색하게 되기 때문이다.

이진탐색트리의 삽입은 탐색을 통해 데이터가 들어갈 자리를 찾아 삽입된다.

아래 바이너리의 단점 트리에서 5를 삽입할 것이다.

이진탐색트리의 삽입 연산은 탐색을 통해 이루어지기 때문에 탐색과 마찬가지로 O(h)의 시간복잡도를 갖게 된다.

또한 삽입은 항상 Leaf 노드에서 이루어지며 트리의 최소값과 최대값은 트리의 가장 왼쪽, 오른쪽이 된다.

이진탐색트리에서 삭제연산은 원하는 노드를 탐색한 뒤 해당 노드를 삭제한다.

이때 이진탐색트리의 구조가 깨질 수 있으므로 삭제 후 기존노드를 이진탐색트리의 조건에 맞게 조정해야 한다.

이진탐색트리의 삭제 연산은 3가지 케이스로 나눌 수 있다.

(1) 삭제하려는 노드의 자식노드가 존재하지 않는 경우

아래 이진탐색트리에서 8을 삭제한다고 했을 때 루트노드부터 탐색하여 8을 찾는다. 8은 자식노드가 존재하지 않으므로 바로 삭제할 수 있다.

(2) 삭제하려는 노드의 자식노드가 1개만 있는 경우

해당 노드를 삭제하고 해당 노드의 자식노드와 부모노드를 연결시켜준다.

아래 이진탐색트리에서 11을 삭제하려고 할 때, 11은 자식노드가 1개만 있는 경우이므로 11을 삭제하고 9와 14를 연결시켜준다.

14를 루트로 하는 서브트리의 모든 키값은 9보다 크기 때문에 그냥 연결해도 이진탐색트리의 조건에 위배되지 않는다.

자식노드가 1개인 경우엔 다음과 같은 경우에도 삭제 후 연결시켰을 때 아무런 문제가 바이너리의 단점 없다.

(3) 삭제하려는 노드의 자식노드가 2개인 경우

해당 노드를 삭제하고 해당 노드의 predecessor(왼쪽 서브트리의 최대값) 또는 successor(오른쪽 서브트리의 최소값)로 대체한다.

predecessor와 successor는 자식노드가 존재하지 않거나 자식노드가 하나만 존재한다.

아래 이진탐색트리에서 9를 삭제할 것이다.

여기서 삭제될 9의 위치에 올 수 있는 노드는 predecessor인 8과 successor인 10이 된다.

8은 9의 왼쪽 서브트리에서 최대값이며 10은 9의 오른쪽 서브트리에서 최소값이기 때문이다.

9를 삭제하고 predecessor인 8을 9의 자리로 옮겼을 때 결과는 아래와 같다.

predecessor인 8은 자식노드가 존재하지 않았기 때문에 9의 위치에 8을 놓고 기존 8의 위치에 있는 노드는 삭제한다.

9를 삭제하고 successor인 10을 옮기는 경우를 보자

이와 같은 결과를 갖게 될 것이다.

여기서 눈여겨 볼 점은 처음에 삭제할 노드 9를 기준으로 successor였던 10은 자식노드를 1개 가지고 있다는 바이너리의 단점 점이다.

이는 자식노드가 1개만 존재하는 삭제연산 두번째 케이스에 해당된다. 따라서 기존 successor 10의 자식노드인 13과 successor 10의 부모노드인 14를 연결시킨 것이고 이진탐색트리의 조건에 위배되지 않는다.

자식노드가 1개인 predecessor를 옮기는 경우도 마찬가지다.

만약 successor 10이 13이라는 자식노드를 가지고 있지 않았다면 자식노드가 존재하지 않았던 predecessor 8을 옮기는 경우와 같다.

바이너리의 단점

MariaDB 10.1 Binary 설치

컴파일보다 비교적 간단한 Binary 설치에 대해 정리해보겠습니다.

Binary는 컴파일이 된 프로그램을 압축해놓은 상태로, 압축만 풀고 간단한 설정만으로도

자신이 원하는 설정대로 조절이 가능하다는 장점이 있습니다.

컴파일의 장점을 갖고 있으면서도 컴파일의 단점인 설치가 복잡하고 오래걸린다는 바이너리의 단점 단점이 보완됩니다.

[[email protected] ~]# useradd mysql

[[email protected] ~]# cd /data

[[email protected] ~]# cd /mdata

[[email protected] ~]# chown mysql:mysql /mdata

[[email protected] data]# tar zxvf mariadb-10.1.18-linux-x86_64.tar.gz

[[email protected] data]# mv mariadb-10.1.18-linux-x86_64 /usr/local/

[[email protected] data]# chown mysql:mysql mariadb-10.1.18-linux-x86_64

[[email protected] data]# chown mysql:mysql mariadb

[[email protected] data]# cd /usr/local/

[[email protected] local]# ln -s mariadb-10.1.18-linux-x86_64 mariadb

[[email protected] local]# cp /usr/local/mariadb/support-files/ my-huge.cnf /etc/my.cnf

[[email protected] local]# cp /usr/local/mariadb/support-files/mysql.server /etc/init.d/mysqld

[[email protected] local]# vi /etc/profile

[[email protected] local]# source /etc/profile

[[email protected] local]# mysql_install_db --basedir=/usr/local/mariadb --datadir=/mdata --defaults-file=/etc/my.cnf

[[email protected] local]# vi /etc/init.d/mysqld

46 basedir= /usr/local/mariadb

47 datadir= /mdata

[[email protected] local]# service mysqld start

Starting MySQL.161018 15:34:35 mysqld_safe Logging to '/mdata/localhost.localdomain.err'.

우리가 Base64를 사용하는 이유

Base64를 사용하는 가장 큰 이유는 Binary 데이터를 텍스트 기반 규격으로 다룰 수 있기 때문이다. JSON과 같은 문자열 기반 데이터 안에 이미지 파일등을 Web에서 필요로 할때 Base64로 인코딩하면 UTF-8과 호환 가능한 문자열을 얻을 수 있다. 끝에 '='과 같은 패딩 기호가 있다면 이는 구분자로써 사용되므로 대부분 Base64로 생각할 수 있다.

기존 ASCII 코드는 시스템간 데이터를 전달하기에 안전하지 않다. 모든 Binary 데이터가 ASCII 코드에 포함되지 않으므로 제대로 읽지 못한다. 반면 Base64는 ASCII 중 제어문자와 일부 특수문자를 제외한 53개의 안전한 출력 문자만 바이너리의 단점 이용하므로 데이터 전달에 더 적합하다.

📮Base 64 인코딩

Base64는 Binary 데이터를 문자로 변환하는데 영향을 받지 않는 공통 ASCII 코드 영역의 문자로만 이루어진 문자열로 바꾸는 Encoding이다. 문자 그대로 64진법(2^6)을 사용하며 Binary 데이터를 6bit 씩 나누고 해당하는 문자를 위의 색인표에서 맞게 치환하는 과정을 거친다. 6bit cut을 진행함에 있어서 모든 문자열이 3개씩 이쁘게 떨어지면 좋겠지만, 아닌 경우도 왕왕 존재하기 마련이다. 그런 경우를 대비해 padding을 하는데 남는자리에 = 기호를 통해서 바이너리의 단점 바이너리의 단점 채워주는 개념이다.

예를들어 '코딩배우는 학생'을 Base64로 인코딩 하면 '7L2U65Sp67Cw7Jqw64qUIO2VmeyDnQ==' 로 2자리의 빈공간을 알려주게 된다. 바이너리의 단점

padding 문자가 반드시 필요한 것은 아닙니다. JSON이나 HTTP 메세지를 통해 데이터 길이를 명시적으로 구분할 수 있다면 더욱 그렇습니다. 하지만 TCP처럼 Stream형태로 데이터를 주고받는 형태에서는 padding이 유용합니다.

📮Base 64 디코딩

복원한 데이터를 다룰 때 주의할 점은 복원한 데이터만 보면 타입을 특정지을 수 없다는 점입니다. 따라서 데이터 형태와 함께 명시하는 경우가 많습니다.


0 개 댓글

답장을 남겨주세요