230112(목)
🎄 성장일지 3.1
책 행복한 이기주의자(웨인 다이어)
의 내용에 자극받아 시작하는 소박한 성장기록
살아있는 꽃과 죽은 꽃은 어떻게 구별하는가?<br/> 성장하고 있는 것이 살아 있는 것이다.<br/> 생명의 유일한 증거는 성장이다!
🌳 키워드 (1.0)<br/> 최대한 간단하게 정리, 추후에 보면서 스스로 설명<br/> 🍉 경험 위주로 (2.0)<br/> 단순 정보를 전달하기보다 무엇을 배웠고 어떻게 해결했는지 짧고 간단하게 작성<br/> ❄️ 정해진 템플릿에 맞춰서 (3.0)<br/> 키워드, 경험 모두 좋다. 다만 매일 작성하기로 마음 먹은만큼 핵심만 간결하게 정리할 수 있게 템플릿을 작성 (3.1) 230102부터 시작되는 학습에 관한 내용 추가
🔑 오늘의 키워드
패딩(바이트 패딩)
바이트 패딩(Byte Padding)이란 구조체(클래스)에 바이트를 추가해 CPU 접근에 부하를 덜어주는 기법
패딩: 속, 충전재 / 불필요하게 넣은 군더더기
좀더 직관적인 설명을 위해 자바 코드를 이해해보자(아주 간단함)
class A { char C; int I; }
위 클래스의 크기는 단순하게 char(1byte) + int(4byte) => 5byte이다.<br/> 하지만 결과적으로는 8byte가 나온다.
위의 경우를 메모리로 살펴보자면 아래와 같다.
C는 1byte, I는 4byte를 차지한다.<br/> 만약 32bit CPU라고 가정했을 때, 32bit CPU는 메모리에서 한 번에 32bit(4byte)를 가져와서 연산한다. 즉, 4byte 단위로 접근을 하게 된다.
이제 C에 값을 대입하면 아래와 같이 4byte 단위로 접근(빨간색)하여 'P'라는 값을 쓴다.
다음 I에 값을 대입할 때는 아래와 같이 2번의 접근을 하게 된다.(한 번으로 안되니까)
위와 같이 I에 값을 쓰기 위해 2번이나 메모리에 다녀와야하는 것은 비효율적이다. 그렇기 때문에 padding을 추가하여 메모리를 조금 낭비하더라도 접근 횟수를 효율적으로 만든다.
아래와 같이 중간에 3byte의 패딩을 알아서 추가하는 개념이다.
class A { char a; 3byte // padding int b; }
이제 C와 I에 값을 대입할 때 4byte 단위로 한 번씩만 메모리에 다녀올 수 있게 된다.
포인터
모든 데이터는 주소값을 갖고 있으면, 우리가 할당하는 것은 그 값 자체라기보단 그 값을 담고 있는 메모리 주소이다.<br/>
이 때, 이 메모리 주소를 담을 수 있는 변수가 포인터 변수
이다. 자바스크립트에는 포인터가 없다. 다만, 비슷하게 표현해보자면 아래와 같다.
const a = 10; /* 0x10a1(임의의 메모리주소)에 10이 할당되고 a에는 0x10a1이 할당되는 것이다. */ const *b = &a; /* b에는 a의 메모리 주소값이 할당된다. */
생각해보면 어차피 a가 메모리 주소를 참조하고 있는데, 무엇때문에 구디 포인터 변수를 만들어서 직접 메모리 주소값을 받아오는걸까?<br/> 메모리 주솟값을 담고 있는 포인트 변수의 이점은 아래와 같다.
- 메모리에 직접 접근이 가능하다.
- 구조화된 자료를 만들어 효율적인 운영이 가능하다.
- Call by reference 방식을 이용할 수 있다.
- 배열, 구조체 등의 복잡한 자료 구조와 함수에 쉽게 접근 가능하다.
- 메모리 동적 할당이 가능하다.
실질적으로 자바스크립트에는 포인터 변수와 같은 개념이 구현되어있지는 않지만, 개념을 이해하고 있도록 하자.
가비지 컬렉션
더 이상 참조되지 않는 값이 가비지 컬렉터에 의해 삭제되는 것.<br/>
let a = { name: 'jayden' }; // a에 다른 객체를 할당 a = { name: 'hodu' };
위의 예시에서 첫 번째 객체를 담은 메모리 주소는 더 이상 참조되지 않게 된다. 어느 곳에도 사용하지 않는 값이 메모리에 남아있으면 낭비이기 때문에 가비지 컬렉터에 의해서 삭제된다.<br/> 자바스크립트 엔진은 실행에 영향을 미치지 않는 다양한 가비지 컬렉션 최적화 기법을 적용한다.
메모리 구조
메모리는 크게 커널 영역과 유저 영역으로 나뉜다.<br/>
커널 영역은 말 그대로 운영체제의 핵심인 커널이 위치하는 영역으로 유저가 접근할 수 없다. 간단하게 메모리 중에서 운영체제(OS)가 시스템 통제를 위해 사용하는 영역이라고 생각하면 된다. 커널 영역이 가장 높은 메모리 주소값들을 갖고 그 다음 스택 영역이 높은 메모리 주소를 갖는다.(이 때, 스택에 값이 저장될 때는 점차 메모리 주소가 낮아지며 저장된다. 이렇게 함으로써 힙 영역과 같은 공간을 공유하고 커널 영역을 침범하지 않게 한다.<br/>
커널 영역을 제외한 유저 영역은 스택 영역, 힙 영역, 데이터 영역, 코드 영역으로 나뉜다. 사실은 엄밀히 따지면 하드디스크에 있는 프로그램을 실행하게 되면 그 프로그램이 메모리에 올라와 프로세스가 되고 이 프로세스마다 (스택, 힙, 데이터, 코드)로 구성된 유저 영역을 갖게 된다. 이 개념이 프로세스 메모리
이다.
스택 영역
- 함수 내에서 지역변수(Local Variable)와 매개변수(Parameter)가 저장되는 영역
- 함수가 호출될 때(실행될 때), 필요한 크기만큼 만들어지며 데이터를 저장해 나간다.
- 지역변수가 저장되는 영역이기 때문에 함수가 끝나게 되면 스택 영역은 소멸된다.
- LIFO(선입선출) 방식으로 저장된다.
- 메모리 주솟값이 높은 곳에서 시작하여 점차 낮아지며 데이터가 저장된다는 특징이 있다.
힙 영역
- 동적할당된 변수가 저장되는 영역
- 필요한 크기만큼 만들어 놓는 스택 영역과 달리 프로그램이 실행되는 도중에 메모리를 할당하는 영역
- 참조형 타입(객체)들이 할당되는 영역이다.
- 콜 스택(스택 영역)과 달리 LIFO 정책을 따르지 않고 랜덤하게 배치된다.
- 메모리 누수를 방지하기 위해 JS엔진의 메모리 관리자(가비지 컬렉터)가 항상 관리한다.(가비지 컬렉션이 발생하는 영역)
참고)
메모리 누수
: 이렇게 더이상 참조되지 않는 메모리가 가비지 컬렉터에 의해 삭제되지 않은 경우를 말한다.(계속 남아서 메모리를 차지하는 경우)
데이터 영역
- 프로그램의 전역 변수와 정적 변수가 저장되는 영역
- 자바스크립트에서는 static으로 구현된 정적 변수는 없다.
- 프로그램의 시작과 함께 할당되고 프로그램이 종료되면 소멸한다.
코드 영역
- 실행할 프로그램의 코드가 저장되는 영역
- CPU에서 코드 영역에 저장된 명령어를 하나씩 가져가 처리하게 된다.
malloc(memory allocation; 메모리 할당)
- memory allocation(메모리 할당)의 약자
- c언어에서 malloc 함수는 프로그램이 실행되는 도중에 상황에 따라 가변적으로 메모리 공간을 사용하게 해준다.(동적 할당)
- ++) 반대로 malloc을 통해 메모리를 할당해주고 다시 사용한 뒤에 다시 할당을 해제해주어야 한다.
- 자바스크립트와 같은 고수준 언어에서는 가비지 컬렉터가 알아서 정리해준다.
- c와 같은 저수준 언어에서는 free 함수를 통해 해제해주어야 한다.
참고 자료
바이트 패딩<br/> 포인터 개념<br/> 포인트를 왜 쓸까?<br/> 자바스크립트-가비지 컬렉션<br/> 메모리 구조(커널영역 포함)
📝 요약 및 하루 간단 회고
저번 CPU에 이어서 메모리에 대한 공부를 진행했다. 그 동안 코어 자바스크립트와 같은 책을 보고 구글링을 하면서 콜 스택이 뭐고 힙이 뭔지에 대해서 막연하게 알고 있었다. 아직도 알아야할 내용들이 많지만, 메모리의 각 영역이 어떻게 구분되어있고 운영체제는 어떻게 메모리를 관리하고 있는지 알게 되었다. 물론 생각보다 메모리와 관련한 자료를 서치하면 c나 자바를 기준으로 설명된 게 많아서, 좀더 자바스크립트와 관련된 방향으로 공부를 할 생각이다. CS 파트가 조금은 지루할 줄 알았는데, 미션이 주어지고 구현을 위주로 하다보니 공부하는 재미도 있고 머리에 더 남는 기분이다. 무엇보다 하드웨어를 정말 간단하게라도 구현해보는 게 재미있는 거 같다!
undefined