블로그

인프런 워밍업 클럽 스터디 2기 - CS 전공지식<10월 셋째주 미션>

운영체제메모리의 종류는 어떤것들이 있나요? 각 메모리의 특징도 함께 적어주세요.(아래로 갈수록 속도는 감소한다. 용량은 증가한다)레지스터 : cpu가 사용하는 메모리 가용 공간이 가장 작고 속도가 제일 빠르다.케시 : 미리 데이터를 저장하는 용도메인메모리 : os와 process가 실행되는 공간보조저장장치 : 비휘발성 데이터 저장소 프로그램이 저장사용자 프로세스가 메모리의 운영체제 영역에 침범하지 못하도록 만든 레지스터는 어떤 레지스터일까요?경계 레지스터메모리 할당 방식에서 가변 분할 방식과 고정 분할 방식의 장단점은 뭔가요?가변 분할 방식프로세스 크기에 따라 메모리를 할당하기에 내부 단변화가 발생하지 않는다.외부 단편화가 발생한다.고정 분할 방식구현 방식이 간단하다.외부 단편화보다 공간 낭비가 심한 내부단편화가 발생한다.CPU 사용률을 올리기 위해 멀티프로그래밍을 올렸지만 스왑이 더 많이 이루어져 CPU 사용률이 0%에 가까워 지는 것을 뭐라고 할까요? 스레싱 HDD나 SSD는 컴퓨터를 실행시키는데 꼭 필요한 걸까요? 일반적으로 운영체제를 HDD 혹은 SDD에 저장합니다. 컴퓨터가 부팅되었을 때, os의 데이터, 코드, 힙영역을 메모리에 올려서 실행합니다. 따라서 현재 사용하고 있는 컴퓨터를 사용하기 위해서는 HDD, SDD가 필요합니다.하지만 경량화된 운영체제를 usb에 저장하거나 운영체제를 사용하지 않는다면, 반드시 필요하다고는 할 수 없습니다.파일을 삭제해도 포렌식으로 파일을 복구할 수 있는 이유가 무엇일까요?파일 시스템은 파일 테이블의 헤더를 삭제하고 free block list에 추가합니다. 따라서 사용한 파일 정보가 남아있기 때문에 포렌식 복구가 가능합니다.자료구조와 알고리즘지금까지 배운 5개의 정렬 알고리즘의 장단점과 시간 복잡도를 적어주세요.거품 정렬: 구현이 간단하다. 하지만 성능이 o(n^2)으로 좋지 않다.삽입 정렬 : 거품정렬과 동일하게 구현이 간단하다. 하지만 이또한 성능이 좋지 않다. o(n^2)선택 정렬 : 배열에서 가장 작은 값을 순차적으로 정렬하는 방법. 위의 정렬 방법과 똑같이 성능이 좋지 않다. o(n^2)병합 정렬 : 재귀적인 방법을 활용하여 데이터를 작은 단위로 나누어 정렬을 진행하여 합치는 방법입니다. 위의 정렬 방법 보다 속도가 더 뛰어납니다. o(n*logn)퀵 정렬 : pivot을 기준으로 데이터를 나눕니다. 이후 pivot을 재외하고 왼쪽 인덱스와 오른쪽 인덱스의 값을 pivot과 비교합니다. 왼쪽인덱스에는 pivot값보다 큰값이 나올때까지 인덱스를 증가하고, 오른쪽 인덱스는 pivot보다 작은 값이 나올때까지 인덱스 값을 감소합니다.만약 각 인덱스가 교차되지 않았다면 양 값을 교환합니다.해당 과정을 서로 교차 될때까지 수행합니다.왼쪽, 오른쪽 인덱스가 교차되었다면, pivot과 오른쪽 인덱스를 교체합니다.해당 방식을 통해 오른쪽 인덱스 값을 기준으로 정렬이 수행됩니다.해당 과정을 왼쪽 인덱스를 기준으로 다시금 반으로 나누어 재귀적으로 수행합니다.해당 방법은 최악의 경우 o(n^2)이고, pivot값을 잘 선택해야 합니다. 하지만 대채적으로 평균 성능인 o(n*logn)을 띄고 더 적은 비교와 메모리 공간을 차지하기 떄문에 병합 정렬보다 퀵정렬이 보다 띄어난 정렬 알고리즘으로 평가합니다.메모리가 부족한 시스템에서 어떤 문제를 해결하는데 재귀로 쉽게 구현이 가능할 것 같습니다. 여러분이라면 메모이제이션과 타뷸레이션 중 어떤 걸 이용하실 건가요? 이유를 함께 적어주세요.타뷸레이션메모제이션의 경우 스택에 계속 새로운 함수를 생성하기에 해당 방식 자체가 메모리를 낭비하게 됩니다. 이에 비해 타뷸레이션은 한번의 함수 호출로 모든 동작을 완료하기 때문에 코드의 작성이 복잡하게 되어도 메모리를 효육적으로 사용하는 것에는 타뷸레이션이 유리합니다.

이선주

인프런 워밍업 클럽 스터디 2기 CS 3주차 과제

운영체제 Q. 메모리의 종류는 어떤것들이 있나요? 각 메모리의 특징도 함께 적어주세요.CPU 레지스터: CPU에서 임의에 변수를 담는 장소로 주기억장치에 데이터를 가져와 레지스터에 저장한다.CPU 캐시(L1, L2, ~): 주기억장치에서 데이터를 가져와 레지스터에 담을 때, 지역성이론에 따라 자주 사용되는 데이터를 캐시에 저장한다.주기억장치(RAM): 주기억장치라고 불리우는 RAM은 어떠한 주소로 데이터를 가져와도 동일한 성능으로 데이터를 가져올 수 있다. 프로세스와 운영체제가 주기억장치에 올라와 실행되는 공간이다. RAM의 또다른 특성은 전원이 공급되지 않으면 데이터가 지워지는 휘발성 메모리이다.보조기억장치: 휘발성 메모리인 RAM은 데이터를 저장하기 보다는 실행되는 데이터를 저장하는데 유용하다. 때문에 작업중인 파일이나 프로그램의 데이터를 보조기억장치에 저장하여 필요할 때 RAM에 올려 사용한다. Q. 사용자 프로세스가 메모리의 운영체제 영역에 침범하지 못하도록 만든 레지스터는 어떤 레지스터일까요?경계 레지스터: MMU가 경계 레지스터에 침범하려고 하는 프로세스를 강제 종료시킨다. Q. 메모리 할당 방식에서 가변 분할 방식과 고정 분할 방식의 장단점은 뭔가요?가변 분할 방식(세그멘테이션): 세그멘테이션은 프로세스의 크기에 맞게 적절한 메모리 크기를 할당하여 불필요한 내부 단편화로 낭비되는 메모리 영역이 없다. 또한, 프로세스 크기에 맞는 메모리 영역을 할당하기 때문에 프로세스 영역별로 권한 등의 관리가 쉽다. 단, 외부 단편화 문제가 있는데, 예를 들어, 프로세스 A가 종료되어 메모리 영역에 구멍이 생길 경우, 새롭게 실행될 프로세스 B가 프로세스 A보다 큰 메모리를 요구한다면 구멍난 메모리 영역에 할당할 수 없게 된다. 이를 외부 단편화 문제라고 부르며 외부 단편화 문제를 해결하기 위해서는 메모리 조각 모음을 실행해야 한다. 하지만, 메모리 조각 모음은 실행중인 프로세스들을 종료하고 구멍난 메모리 영역을 매꿔야하기 때문에 오버헤드가 발생한다.고정 분할 방식(페이징): 페이징은 세그멘테이션과 다르게 고정된 메모리 크기를 분할하여 프로세스들에게 할당하는 방식이다. 때문에 고정된 크기보다 작은 프로세스를 실행하려 한다면 메모리 낭비가 발생하게 되는데 이를 내부 단편화라 부른다. 하지만, 항상 고정된 크기의 메모리를 분할하여 프로세스에게 할당하여 세그멘테이션의 외부 단편화 문제가 없다. Q. CPU 사용률을 올리기 위해 멀티프로그래밍을 올렸지만 스왑이 더 많이 이루어져 CPU 사용률이 0%에 가까워 지는 것을 뭐라고 할까요?정답: 스레싱, 이를 해결하기 위해 지역성이론에 따라 다시 현재 사용중인 페이지들은 다시 사용될 확률이 높다. 이러한 페이지를 하나로 묶어 메모리에 올리는데 이를 워킹셋이라고 부른다. Q. HDD나 SSD는 컴퓨터를 실행시키는데 꼭 필요한 걸까요? (이유를 함께 적어주세요.)HDD나 SSD와 같은 보조기억장치가 필요한 이유는 다음과 같다.CPU 레지스터나 캐시, 주기억장치는 휘발성 메모리이다. 때문에 작업했던 문서나 프로그램의 데이터 등 유지시킬 필요가 있는 상태들은 전원 공급 없이도 보조기억장치를 통해 상태를 저장해야 한다.또한, 메모리는 가격이 매우 비싸기 때문에, 메모리보다 저렴한 보조기억장치에 문서나 데이터를 저장하고 프로그램이 실행될 때 프로세스로 메모리에 올리는 방식이 효율적이다.보조기억장치에는 운영체제 프로그램을 담고 있다. 컴퓨터가 실행하면 보조기억장치에 있는 운영체제를 메모리에 올려 프로세스로 실행하게 된다.Q. 파일을 삭제해도 포렌식으로 파일을 복구할 수 있는 이유가 무엇일까요?이는 파일을 삭제할 때 파일의 헤더만 삭제하기 때문이다. 때문에 사용했던 블록의 데이터는 그대로 남아있어 포렌식을 통해 데이터를 복구할 수 있게 된다.파일을 삭제할 때 헤더만을 삭제하여 Free Block List에 추가한다. 그리고 해당 블록은 "사용 가능" 상태로 두어, 새로운 파일을 작성할 때 해당 영역에 덮어쓰기하게 된다. 이러한 방식을 통해 모든 파일을 지울 때 발생하는 디스크 입출력에 대한 부담을 줄여주어 성능을 끌어올리고, 데이터 복구 가능성 또한 열어두는 것이다.  자료구조와 알고리즘 Q. 지금까지 배운 5개의 정렬 알고리즘의 장단점과 시간 복잡도를 적어주세요.버블정렬: 현재 요소와 다음 요소를 비교하며 정렬하는 알고리즘으로 구현이 쉽지만 중첩 for 문을 사용하기 때문에 성능이 좋지 않다. 단, 정렬하려는 요소의 다음 요소를 비교하기 떄문에 안정적인 정렬 알고리즘이다. | O(n^2) |선택정렬: 정렬된 영역과 정렬되지 않은 영역을 나누어, 정렬되지 않은 영역에서 가장 작은 (또는 가장 큰) 값을 선택해 정렬한다. 구현이 쉽지만 버블정렬과 마찬가지로 중첩 for 문을 사용하기 때문에 성능이 좋지 않다. 단, 버블 정렬보다 교환 횟수가 상대적으로 적은데 이는 큰 배열에서 선택 정렬이 상대적으로 빠르다. | O(n^2) |삽입정렬: 정렬되지 않은 영역의 요소를 정렬된 영역의 적절한 위치에 삽입하는 알고리즘으로 구현이 쉽다는 장점이 있지만 중첩 for 문을 사용하기 때문에 성능이 좋지 않다. | O(n^2) |병합정렬: 정렬할 배열을 반으로 나누는데 더 이상 나눌 수 없을 때까지 반으로 나눈 후, 다시 역순으로 비교하며 병합하는 알고리즘이다. 재귀적으로 해결하기 때문에 이해 및 구현이 어렵다. 또한, 배열을 반으로 나누는 방식으로 비교적 많은 메모리 공간을 사용한다. 단, 버블/선택/삽입 정렬보다 빠른 성능을 가진다는 장점이있다. | O(nlogn) |퀵정렬: '피벗'이라는 배열의 기준이 되는 요소를 선택한 후 재귀적 호출을 통해 정렬하는 알고리즘이다. 퀵정렬은 어떤 피벗을 선택하느냐에 따라 최악의 성능인 O(n^2)이 나올 수 있다. 하지만, 매번 최악의 피벗 선택을 하는 것은 극히 낮으며, 병합정렬보다 메모리 공간을 덜 사용하기 때문에 병합정렬보다 퀵정렬이 더 좋은 평가를 받는다. | O(nlogn) | Q. 메모리가 부족한 시스템에서 어떤 문제를 해결하는데 재귀로 쉽게 구현이 가능할 것 같습니다. 여러분이라면 메모이제이션과 타뷸레이션 중 어떤 걸 이용하실 건가요? 이유를 함께 적어주세요.재귀적으로 호출하는 상황에서 메모리 부족 문제를 해결하기 위해서는, 이미 해결한 문제를 저장하여 불필요한 연산과 콜스택 낭비를 해결할 수 있다. 이를 메모이제이션이라고 부른다. 메모이제이션으로 메모리 부족 문제를 해결하는 방식은 값을 저장할 해시 테이블을 두고 재귀적으로 해결할 문제를 해시 테이블의 키 값으로 저장한다. 이후 같은 문제가 재귀적으로 호출 될 때 해시 테이블을 조회하여, 이미 해결된 문제라면 해당 키에 해당하는 값을 이용하여 메모리 낭비를 해결할 수 있다. 이러한 방식에서 해시 테이블을 이용하는 이유는, 해시 테이블의 특성상 키를 이용한 조회가 O(1) 시간으로 빠르게 값을 찾을 수 있기 때문이다.

알고리즘 · 자료구조

양성빈

인프런 워밍업 스터디 클럽 2기 백엔드(클린코드, 테스트코드) 4주차 발자국

이 블로그 글은 박우빈님의 인프런 강의를 참조하여 작성한 글입니다.드디어 마지막 발자국 작성차례이다. 어느덧 벌써 수료날짜가 얼마 남지 않았다. 남은 시간 끝까지 달려보자. Presentation Layer 테스트외부세계의 요청을 가장 먼저 받는 계층파라미터에 대한 최소한의 검증을 수행MockMVCMock 객체를 사용해 스프링 MVC 동작을 재현할 수 있는 테스트 프레임워크요구사항관리자 페이지에서 신규상품을 등록할 수 있다.상품명, 상품타입, 판매상태, 가격등을 입력받는다. 그래서 해당 요구사항으로 비즈니스 로직을 작성 후 해당 부분 테스트를 해보았다. 여기서 잠깐 주목할만한 부분이라면 바로 @Transactional(readOnly = true)와 @Transactional이다. readOnly옵션은 읽기 전용이라는 뜻이다. 해당옵션에서는 CRUD중에 R만 기능동작을 하게 한다. 또한 JPA에서 CUD스냅샷 저장과 변경감지를 하지 않아 성능향상에 이점을 줄 수 있다. 또한 CQRS에서 Command부분과 Read부분을 나누자는 것처럼 우리의 비즈니스 로직중에 해당 클래스를 readOnly옵션을 전체로 주고 CUD에 해당되는 부분만 @Transactional을 사용하자!또한 우리는 validation을 적용하고 예외를 처리하기 위해 spring-boot-starter-validation 의존성을 추가해주고 각 dto에 어노테이션들을 추가해주었다. 또한 각 예외상황에 맞게 처리할 RestControllerAdvice를 두었으며 공통응답객체를 만들어 진행을 해보았다. 여기서 유심히 볼 부분이 몇가지 존재한다.⚠ @NotBlank vs @NotNull vs @NotEmptyNotNull은 null값을 허용을 하지 않는 것이고 NotEmpty는 ""문자열만 허용을 하지 않으며 NotBlank는 이 둘을 다 포함하면서 " "문자열도 포함시키지 않는다.또한 해당 request DTO를 만들면서 하나의 DTO를 이용해서 presentation layer부터 Business Layer까지 쓰이곤 한다. 이런 점은 DTO를 두고 의존성을 둘 수 있다는 것이다. 이건 layered architecture에 어긋한다. 따라서 서비스용 DTO, 컨트롤용 DTO를 별도 개발해서 진행을 해보는 작업을 해보았다. 또한 컨트롤러에서는 최소한의 검증을 하고 그 외에는 서비스용으로 옮겨보는 법도 생각해보았다. 미션이번 미션은 레이어 아키텍쳐에 관하여 설명과 테스트 방법에 대해 나만의 언어로 풀어쓰는 미션이다. 처음에는 내 언어로 표현한다는게 막막했지만 차근차근 정리를 해가다보니 금방 쉽게 풀어써졌다.미션링크 Mockito로 Stubbing하기요구사항현재 관리자 페이지에서 당일 매출에 대한 내역을 메일전송을 받고 싶어한다.그래서 우리는 해당 요구사항을 바탕으로 비즈니스 로직을 작성하였다. 핵심은 테스트이다. 메일 전송은 외부 네트워크를 타고 전송이 되는 로직이라 매우 오랜 시간이 걸린다.(내 경험) 또한 메일을 계속 보내다보면 나중에 수 많은 테스트 메일이 쌓여 있는 것을 알 수 있다. 이럴때는 어떻게 할까? 메일 전송 행위자체를 mocking하면 되는데 이것을 stubbing이라고 한다. 우리는 메일 전송 로직을 mockBean을 이용해 mocking하고 행위 자체를 stubbing하여 테스트를 수행 할 수 있었다. Test Double출처배우 대역의 스턴트맨이 그 Test Double의 근원지이다.관련 용어Dummy: 아무것도 하지 않는 깡통객체Fake: 단순한 형태로 동일한 기능은 수행하나 프로덕션에서 쓰기에는 부족한 객체(ex. FakeRepository)Stub: 테스트에서 요청한 것에 대해 미리 준비한 결과를 제공하는 객체. 그 외에는 응답XSpy: Stub이면서 호출된 내용을 기록하며 보여줄 수 있는 객체. 일부는 실제 객체러첨 동작시키고 일부만 stubbingMock: 행위에 대한 기대를 명세하고 그에 따라 동작하도록 만들어진 객체 Stub과 Mock을 헷갈려한다. 동일한거 아닌가? 결론부터 말하자면 Mock은 Stub이 아니다. Mock은 행위에 대한 검증을 할때 사용하고 Stub은 상태에 대한 검증을 할때 사용된다. @Mock, @Spy, @InjectMocks순수 Mockito로 검증하는 시간을 가져보았다. 우리는 @SpringBootTest를 붙여서 통합 테스트를 가져보았는데 그렇게 하지 않고 순수 Mockito로 테스트할 수 있는 방법은 없을까?그래서 우리는 기존에 MailService를 테스트를 가져보았다. 의존성으로 주입된 것들을 mock()을 이용하여 만들어주고 MailService를 해당 mock()으로 만든 것을 생성자에 넣어주어서 실행했다.하지만 이렇게 하는것보다 더 좋은 방법은 @Mock과 @InjectMocks를 이용하는 방법이다. mock()으로 생성한 객체는 @Mock 어노테이션을 붙여서 사용이 가능하고 만들어진 mock 객체를 이용하여 생성한 객체 MockService는 @InjectMocks를 이용하여 더 간단히 사용이 가능하다. 추가적으로 해당 메서드 안에 특정메서드가 몇번 불렸는지 확인하는 것은 verify로 확인이 가능하다.@Mock을 사용할 때는 @ExtendWith(MockitoExtension.class)을 붙여줘야 한다.또한 @Spy를 이용할건데 사용법은 @Mock과 유사하다. 다른점은 @Mock을 사용할때 when().thenReturn()식을 이용했는데 @Spy는 doReturn().when().메서드()를 이용하면 된다. @Mock과 비교해보자. @Mock을 사용하면 해당 메서드만 mocking을 하여 사용하고 그 외의 메서드들은 작동을 안 한다. 하지만 @Spy를 사용하면 해당 객체에 호출한 메서드들이 전부 작동이 된다. 그래서 일반적으로 @Mock을 사용하지만 @Spy를 이용할 때도 있으니 알아두자. BDDMockitoBDD는 행위주도개발로 이전에 한번 살펴본 적이 있다. 이전에 실습한 코드를 보면 뭔가 이상하다고 느낄 수 있을 것이다.// given when(mailSendClient.sendEmail(anyString(), anyString(), anyString(), anyString())).thenReturn(true);분명 given절인데 when이 들어가져 있다. 그래서 만들어진 것이 BDDMockito다. BDDMockito의 given을 이용하면 아래와 같이 변경이 가능하다.given(mailSendClient.sendEmail(anyString(), anyString(), anyString(), anyString())).willReturn(true);그럼 정확히 given에 given을 이용하니 명확해진다. Classicist VS. MockistClassicist입장은 다 mocking하면 실제 객체들의 동작 및 두 객체들이 합쳐서 동작할때 그에 따른 사이드 이펙트는 어떻게 검증할건데라는 입장이며 Mockist 입장은 모든 걸 다 mocking하면 각 객체들의 기능에 대한걸 보장하니 굳이 통합테스트를 할 필요가 없다라는 입장이다.우리는 Persistence Layer에서 단위 테스트를 진행하고 Business Layer에서는 통합 테스트를 Presentation Layer에서 두 레이어를 모킹하여 진행했다. 이것을 Mockist가 본다면 굳이 시간낭비하고 있다고 할 것이다.우빈님의 생각은 Classicist입장이시며 mocking을 할때는 외부시스템을 사용할 일이 있을때 사용한다고 하셨다.즉 결론은 mocking을 했다 하더라도 실제 프로덕션 코드에서 런타임 시점에 일어날 일을 정확하게 stubbing했다 단언할 수 없으니 통합테스트를 해보자는 것 같다.나의 입장은 이렇다. QuerDSL같은 외부자원을 사용할때 나는 해당 부분을 테스트할때 테스트를 진행하고 비즈니스 레이어에는 해당 부분을 mocking처리한다. 그리고 컨트롤러 부분에서 통합테스트를 사용하는데 이 부분은 한번 질문을 드려봐야겠다. 한 문단에 한 주제이전 강의인 Readable Code에서도 배웠고 학창시절 영어독해시간에도 배웠듯이 한 문단에는 하나의 주제로 이루어져야 한다. 테스트도 문서다. 즉, 각각 하나의 테스트는 하나의 문단이고 그 테스트 코드는 하나의 주제를 가져야 한다. 완벽하게 제어하기테스트 코드를 작성할 때는 모든 조건들을 완벽히 제어가 가능해야 한다. 우리는 이전에 LocalDateTime.now()을 사용하면서 현재시간에 따라 테스트가 성공할때도 있고 실패할때도 있는 경우를 보았다. 그래서 우리는 이를 해결하기 위해 이 현재시간을 상위에 넘기고 파라미터로 받는 방식을 택하였다.그러면 만약에 LocalDateTime.now()를 사용해도 테스트가 무조건 성공한다면 사용해도 되나? 우빈님께서는 지양한다고 하셨다. 그 이유는 그 테스트는 성공할진 몰라도 팀 단위에서 해당 코드를 사용하면 그게 프로젝트에 번져서 빈번히 사용할 확률이 높기때문이라고 하셨다. 나도 이점을 한번 주의해야겠다. 테스트 환경의 독립성을 보장하자테스트 환경은 대부분 given절에서 환경을 세팅한다. 그런데 이런 given절에서 다른 API를 사용하게 된다면 어떻게 될까? 해당 API와 테스트 코드가 결합도가 생기게 된다. 이런 부분을 방지하고 테스트코드 독립성을 보장시켜야 한다.@Test @DisplayName("재고가 부족한 상품으로 주문을 생성하려는 경우 예외가 발생한다.") void createOrderWithNoStock() {     // given     LocalDateTime registeredDateTime = LocalDateTime.now();     Product product1 = createProduct(BOTTLE, "001", 1000);     Product product2 = createProduct(BAKERY, "002", 3000);     Product product3 = createProduct(HANDMADE, "003", 5000);     productRepository.saveAll(List.of(product1, product2, product3));     Stock stock1 = Stock.create("001", 2);     Stock stock2 = Stock.create("002", 2);     stock1.deductQuantity(1); // @todo     stockRepository.saveAll(List.of(stock1, stock2));     OrderCreateServiceRequest request = OrderCreateServiceRequest.builder()             .productNumbers(List.of("001", "001", "002", "003"))             .build();     // when & then     assertThatThrownBy(() -> orderService.createOrder(request, registeredDateTime))             .isInstanceOf(IllegalArgumentException.class)             .hasMessage("재고가 부족한 상품이 있습니다."); }위의 코드에서 todo부분을 살펴보자. 해당 코드는 주문생성관련 로직이다. 그런데 deductQuantity를 현재 재고보다 많이 차감시키면 해당 메서드에서 예외를 던질 것이다. 그러면 given절에서 테스트가 실패되고 내가 위에서 말했던 결합도가 생긴 케이스이다. 또한 이건 내 생각이지만 주문생성로직에 재고차감로직이 들어가 있으니 하나의 테스트코드에 주제가 2개가 되버리는 상황이 생긴다. 이런것을 방지하는 것이 좋다. 테스트 간 독립성을 보장하자테스트는 각각 수행되어야 하고 테스트 순서가 무작위여도 같은 결과가 나와야 한다. 하지만 만약 테스트에 공유자원을 사용하게 되면 예상치 못한 결과가 나올 우려가 있기에 테스트가 실패할 경우도 있을 것이다. 이런 점때문에 공유자원 사용은 지양하자. 한 눈에 들어오는 Test Fixture 구성하기Test FixtureFixture: 고정 틀, 고정되어 있는 물체 (given절에 생성한 객체들)테스트를 위해 원하는 상태로 고정시킨 일련의 객체 우리는 이에 관련해서 @BeforeEach BeforeAll에 대해 알아보았다. 그런데 @BeforeEach같은 경우 given절에서 만든 데이터를 넣는 행위는 지양하다고 하셨다. 결국 이것은 이전에 봤던 공유자원과 같은 역할을 한다. 또한 테스트는 문서인데 given절을 보려니 없어서 스크롤로 위로 왔다갔다 하는 상황이 발생하기 때문에 테스트 문서의 파편화가 일어난다.그러면 언제 @BeforeEach를 쓸까? 각 테스트 입장에서 봤을 때 아예 몰라도 테스트 내용을 이해하는데 문제가 없는가?라는 물음과 수정해도 모든 테스트에 영향을 주지 않는가?라는 물음에 괜찮다면 사용하자! 그렇지 않다면 지양하자.또한 data.sql을 이용해 미리 쿼리를 생성해 given절을 작성하는 행위는 지양하자. 왜냐하면 테스트 파편화가 일어나기도 하고 나중에 실무에 가면 수십개의 컬럼과 수십개의 테이블이 있고 이 테이블이나 컬럼이 바뀔때마다 수정을 해줘야 하기때문에 관리포인트가 늘어나기 때문이다.또한 given절에 객체를 생성 시, 필요한 파라미터만 주입받는것을 고려하면 작성하자. 해당 파라미터를 보고 이 파라미터는 테스트에 전혀 영향을 주지 않을 것 같은 것은 고정값으로 두고 파라미터를 빼는 것처럼 말이다.마지막으로 builder와 같이 given절에 들어가는 것을 하나의 테스트 config 클래스에 모아두는 행위는 지양하자. 왜냐하면 나중에 실무에서 작성하다보면 새로운 빌더가 생기고 메서드 오버로딩때문에 파라미터 순서만 바뀌는 빌더도 많이 생길 수 있으며 테스트 문서 파편화로 인해 더 불편해질 것 같다. 그래서 클래스마다 필요한 파라미터만 받아서 작성하는 것이 좋다. Test Fixture 클렌징deleteAll()과 deleteAllInBatch()에 차이에 대해 알아보자. 우빈님은 deleteAllInBatch()를 더 선호하신다고 하셨다. 그 이유에 대해 알아보자.deleteAllInBatch()는 delete from~ 절만 나가는 순수 테이블 전체 삭제에 용이하다. 하자민 단점이라하면 순서를 잘 생각해야 한다. 만약 A라는 테이블과 B라는 테이블이 M:N 연관관계를 맺어 중간테이블 AB라는 테이블이 있을때 AB부터 테이블을 삭제해주고 A, B순서대로 삭제를 해줘야 한다. 그렇지 않으면 예외가 발생한다.deleteAll()은 굳이 중간테이블을 삭제할 필요없이 중간테이블을 알고 있는 테이블만 삭제해도 알아서 삭제해준다. 하지만 단점은 해당 메서드를 실행하면 해당 엔티티를 먼저 전체 select를 하고 다음으로 delete from where 절이 나간다. 그리고 해당 절은 테이블에 있는 데이터 수 만큼 나가기 때문에 수많은 데이터가 존재하면 성능이 매우 떨어질 것이다.그래서 deleteAllInBatch()가 더 선호하는 이유를 알 것 같다. 하지만 이런것보다 side effect를 잘 고려해서 @Transactional을 잘 사용하는 것이 베스트일 것 같다. @ParameterizedTest테스트 코드에 if-else나 for문같이 조건문, 반복문등 읽는 사람의 생각이 들어가는 것을 지양해야한다고 말했다. 그래서 여러가지 테스트 로직이 하나의 테스트 코드에 있다면 분리하자고 하였다. 그런데 만약 단순히 값 여러개로 하나의 테스트를 하고 싶은경우 테스트를 나누는 것보다 @ParameterizedTest를 사용하는 것이 깔끔해진다.대표적인 예시로 내가 사이드프로젝트에서 작성했던 코드를 들 수 있을 것 같다.@ParameterizedTest @MethodSource("providedTestDataForSignup") @DisplayName("회원가입 통합 테스트 - 실패(유효하지 않은 회원가입 폼)") void member_signup_integration_test_fail_caused_by_invalid_signup_form(String name, String nickname, String email, String password, String confirmPassword, String phoneNumber, LocalDate birthday) throws Exception {     MemberSignupRequestDto requestDto = new MemberSignupRequestDto(name, nickname, email, password, confirmPassword, phoneNumber, birthday);     this.mockMvc.perform(post("/api/auth/signup")                   .contentType(MediaType.APPLICATION_JSON + ";charset=UTF-8")                     .accept(MediaType.APPLICATION_JSON + ";charset=UTF-8")                     .content(this.objectMapper.writeValueAsString(requestDto)))             .andDo(print())             .andExpect(status().isBadRequest())             .andExpect(jsonPath("message").exists())             .andExpect(jsonPath("status").value(GlobalExceptionCode.INVALID_REQUEST_PARAMETER.getHttpStatus().name()))             .andExpect(jsonPath("code").value(GlobalExceptionCode.INVALID_REQUEST_PARAMETER.getCode()))             .andExpect(jsonPath("timestamp").exists()); } private static Stream<Arguments> providedTestDataForSignup() {     return Stream.of(             Arguments.of("양성빈", "tester", "email@email.com", "1q2w3e4r5t!", "1q2w3e4r5t!", "010-1234-1234", LocalDate.of(1999, 1, 1)),             Arguments.of("양성빈", "robert", "test@email.com", "1q2w3e4r5t!", "1q2w3e4r5t!", "010-1234-1234", LocalDate.of(1999, 1, 1)),             Arguments.of("양성빈", "robert", "email@email.com", "1q2w3e4r5t!", "t5r4e3w2q1@", "010-1234-1234", LocalDate.of(1999, 1, 1)),             Arguments.of("양성빈", "robert", "email@email.com", "1q2w3e4r5t!", "1q2w3e4r5t!", "010-1111-1111", LocalDate.of(1999, 1, 1))     ); }이렇게 @MethodSource를 사용하는 경우 이외에오 @CsvSource를 이용하는 경우도 있고 다른 방법도 있으니 한번 찾아보면 좋을 것 같다. @DynamicTest공유변수를 가지고 여러개의 테스트가 사용하는 것은 지양하자고 하였다. 왜냐하면 테스트의 순서가 생겨버리고 서로 강결합이 되기 때문이다. 하지만 환경 설정 후 시나리오 테스트를 하는 경우가 있을 것이다. 그럴 경우 @DynamicTest를 이용하자. 사용법은 아래와 같다.@TestFactory @DisplayName("") Collection<DynamicTest> dynamicTests() {     // given     return List.of(             DynamicTest.dynamicTest("", () -> {                 // given                 // when                 // then             }),             DynamicTest.dynamicTest("", () -> {                 // given                 // when                 // then             })         ); } 테스트 수행도 비용이다. 환경 통합하기이제 전체 테스트를 돌려보자. 지금 테스트를 전체 돌려보면 2.x초라는 시간이 걸리고 spring boot 서버가 6번 뜨는 불필요한 행위가 발생한다.테스트 코드를 작성하는 이유가 인간의 수동화된 검증에 대한 불신도 있지만 가장 큰 이유는 시간을 아끼기 위해서이다. 하지만 테스트를 돌렸는데 2.x초라는 행위는 너무 아깝다. 그래서 우리는 하나의 통합추상 클래스를 만들어 service와 repository부분을 하나의 추상클래스를 상속받게 함으로 테스트 띄우는 횟수를 줄였다. 그리거 마지막 controller부분도 별도의 추상클래스를 만들어 해당 클래스를 상속받게 함으로 서버 띄우는 횟수를 줄여갔다. 결론적으로 총 서버는 2번 띄워졌고 2.x초에서 1.x초로 속도가 줄어갔다. Q. private 메서드의 테스트는 어떻게 하나요?정답은 할 필요도 없고 하려고 해서도 안된다. 클라이언트 입장에서는 제공되는 public 메서드만 알 수 있고 알아야하며 그 외의 내부 메서드는 알 필요가 없다. 또한 public 메서드를 테스트한다는 것은 내부 private 메서드도 자동으로 같이 테스트하는 것이므로 따로 테스트를 할 필요가 없다. 다만 만약 이렇게 해도 계속 위의 물음이 생각나면 객체를 분리할 시점인가를 검토해야한다. 그리고 객체를 분리시켜 해당 private 메서드를 해당 객체의 public 메서드로 두고 단위 테스트를 진행해야 할 것이다.나는 미션을 진행하면서 이런 물음이 생각났고 private 메서드를 리플렉션을 통해 테스트를 한 경우가 있는데 위의 해답을 듣고 나니 괜히 테스트를 한것이구나라는 생각이 들어 조금은 반성하게 된 계기였다. Q. 테스트에서만 필요한 메서드가 생겼는데 프로덕션 코드에서는 필요 없다면?답변은 만들어도 된다. 다만 보수적으로 접근해야 한다. 즉, 어떤 객체가 마땅히 가져도 되고 미래지향적이면 만들어도 상관없다. 학습 테스트잘 모르는 기능, 라이브러리, 프레임워크를 학습하기 위해 작성하는 테스트여러 테스트 케이스를 스스로 정의하고 검증하는 과정을 통해 보다 구체적인 동작과 기능을 학습관련 문서만 읽는 것보다 훨씬 재밌게 학습  Spring REST Docs테스트 코드를 통한 API 문서 자동화 도구API 명세를 문서로 만들고 외부에 제공함으로써 현업을 원활하게 한다.기본적으로 AsciiDOC을 사용하여 문서를 작성한다. Spring REST Docs vs SwaggerSpring REST Docs장점테스트 코드를 통과해야 문서가 만들어진다. (신뢰도가 높다)프로적션 코드에 비침투적이다.단점코드 양이 많다.설정이 어렵다.Swagger장점적용이 쉽다문서에서 바로 API 호출을 수행해볼 수 있다.단점프로덕션 코드에 침투적이다.테스트와 무관하기 때문에 신뢰도가 떨어질 수 있다. 미션3 진행테스트코드의 마지막 미션을 진행하였다. 이번에 배운 어노테이션들, @BeforeEach가 적용하여 BDD 스타일 적용하는 실습등 미션을 진행했는데 해당 미션을 통해서 해당 어노테이션들에 대해 확실히 알 수 있었으며 BDD 스타일이 조금 적응된 것 같다.미션링크 깜짝 특강Day18 미션 공통 피드백핵심은 중복 제거가 아니고 도메인이다. 사용자, 게시물은 간접적이므로 setup()으로 댓글은 직접적이므로 given절에 배치해야 한다.Q&A잘문) REST API의 조건 중 하나인 hateoas에 대해 실무에서 많이 사용하는지와 제가 제대로 적용하고 있는지답변) 아직까지 사용한 곳을 본적이 없다고 하셨다. 그 이유를 생각해보시는데 단순히 hateoas를 적용하기에는 APP-FE-BE 간 긴밀한 스펙과 복잡한 동작들이 너무 많고 또 이미 만들어져 있는 구조를 hateoas 형태로 전환한다는것은 불가능에 가깝다고 느끼신다고 하셨다. 또한 실무에서는 대부분 그런 규칙을 지키는 것보다 다른 중요한 것들이 더 많다고 판단하기 때문이라고도 하셨다.코드리뷰우빈님께서 많은 칭찬을 해주셔서 몸둘 바를 모르겠지만 몇가지 피드백 사항이 있었다. 그 중에 제일 생각나는 피드백을 말하면 다음과 같다. given / when / then절에 설명하는 주석은 생략해도 좋다. 하지만 given절이 몇십줄이고 서로 다른 특징들이 나열되어 있다면 간단히 적는 걸 추천하신다고 하셨다.이것으로 모든 워밍업 클럽 진도가 완료가 되었다, 나 자신에게도 뜻 깊은 경험과 성장이 되었으며 이러한 경험의 반복을 이뤄나가고 싶다.

백엔드인프런워밍업스터디클럽2기백엔드클린코드테스트코드발자국

강지원

[인프런 워밍업 스터디 클럽 2기 FE] 강지원 과제 제출

<JavaScript 과제> Day 2 Mission (음식 메뉴 앱)github : https://github.com/noaprost/inflearn_study_js_mission/tree/main/mission1개발 시간 : 3시간개발 순서메뉴 정보를 담을 menu.json 파일을 만들었습니다.fetch를 사용하여 json 데이터를 불러오고 main 부분에 동적으로 child를 추가해주었습니다.각 카테고리 button에 onClick eventListener를 달아주고 curCategory 변수를 선언하여 현재 클릭 된 카테고리가 무엇 인지에 따라 다른 child가 main에 보여지도록 했습니다.아쉬웠던 점useEffect나 useState를 대체할 코드를 js로 짜는 것이 미숙해서 코드가 깔끔하게 짜이지 않은 것 같아 아쉽습니다.카테고리 버튼을 누를 때마다 main에 이미 있는 child를 모두 제거 후 다시 필터링해서 append 해주었는데, 코드가 비효율적인 것 같아서 아쉽습니다.느낀 점첫 과제를 무사히 끝내서 다행이다. 이번 과제는 바닐라 js로만 앱을 만든 것이 3년전 이후로 처음이라 많이 해맸지만 앞으로의 과제를 만들면서 js 실력이 많이 길러질 것 같아서 기대가 됐다. main 화면Breakfast를 클릭한 화면  Day 3 Mission (가위 바위 보 앱)github : https://github.com/noaprost/inflearn_study_js_mission/tree/main/mission2개발 시간 : 2시간구현 사항가위, 바위, 보 버튼을 누르면컴퓨터에서 랜덤 변수를 생성하고 플레이어와 승패를 비교합니다.승패에 따라 승리 횟수를 업데이트 해주고, 남은 횟수를 1 감소 시킵니다.남은 횟수가 모두 소진됐을 경우최종 승리 횟수를 비교해서 알맞는 문구를 띄워주고 replay 버튼을 보여줍니다.replay 버튼을 누를 경우모든 횟수가 초기화됩니다. 느낀 점한번 만들어봤던 앱이라서 바로 만들기부터 시작했는데, 중간에 막혀서 고생했다ㅠ 구현할 기능과 순서를 다시 쭉 적어 놓고 구현하니까 순조롭게 만들어져서 요구 사항 작성의 중요성을 다시 한번 깨달았다. main 화면 (게임 중)게임이 끝난 화면  Day 4 Mission (퀴즈 앱)github : https://github.com/noaprost/inflearn_study_js_mission/tree/main/misson3개발 시간 : 2시간구현 사항랜덤으로 1~50사이의 수를 골라서 문제를 생성합니다.랜덤으로 정답+랜덤 수 / 랜덤 수1+랜덤 수2+정답이 없습니다. 둘 중 하나를 보여줍니다.정답을 누를 경우 Next 버튼이 보여지고 버튼을 클릭하면 다음 문제로 이동합니다.문제를 틀렸을 경우 Restart 버튼이 보여지고 버튼을 클릭하면 새로운 문제를 보여줍니다. 아쉬웠던 점정답/틀린 답을 클릭했을 경우 ui를 보여줄 때 class 이름을 추가하고 삭제하는 방식으로 구현했는데, if문도 많이 중첩되어있고 긴 코드를 작성한 것 같아서 아쉽습니다. 추후에 더 나은 코드로 리팩토링을 하고 싶습니다. 만족한 점답 버튼을 최대한 랜덤으로 보이게 하고 싶어서 수를 먼저 만들고 이후에 동적으로 생성한 점이 만족스럽습니다. 느낀 점생각보다 구현할 때 신경 쓸 부분이 많았고, ui 처리가 어려웠지만 재밌게 만들었다. 영상에 요구 사항이 잘 안보여서 규칙 등을 직접 정하면서 만들었는데 그 점도 재밌었다. 문제를 띄운 화면정답을 클릭했을 경우오답을 클릭했을 경우  Day 5 Mission (책 리스트 나열 앱, Github Finder 앱) 책 리스트 나열 앱github 주소 : https://github.com/noaprost/inflearn_study_js_mission/tree/main/mission4개발 시간 : 1시간구현 순서form을 만들어서 input 값 2개를 받는다.submit 버튼을 누르면 input에 있던 값을 다른 변수에 저장해둔다.데이터를 가공해서 리스트에 책 제목과 저자, 삭제 버튼을 담은 목록을 보여준다.삭제 버튼을 누르면 해당 리스트가 삭제된다.느낀 점이번 과제는 개인적으로 정말 쉬웠다. todo 앱 강의를 먼저 듣고 나서 만들어서 그런지 가장 명확하게 구현 순서가 그려져서 재미있었다. 책 생성 화면책 삭제 화면Github Finder 앱github 주소 : https://github.com/noaprost/inflearn_study_js_mission/tree/main/mission5개발 시간 : 7시간구현 순서Github api로 user정보와 repo정보를 가져온 후, repo 정보는 최근에 작성된 것이 먼저 보여지도록 정렬한다.displayUserInfo와 displayLatestRepo 함수를 이용해서 각각의 정보를 화면에 보여준다.필요한 정보 정리// user data에서 가져올 목록 // 맨위 4개 태그 public_repos public_gists followers following // 리스트 info company blog location created_at // View Profile 버튼 html_url // 최근 리포 baseUrl repos_url // repo data에서 가져올 목록 // Latest Repos name -> html_url 이용해서 이동할 수 있도록 stargazers_count watchers_count forks_count 어려웠던 점새로운 user를 검색할 때 마다 userInfo와 latestRepo 컨테이너에 담긴 정보들을 지워주고 새로 담아야 하는데, 아래의 간단한 코드를 떠올리지 못해서 3시간이나 해맸다.document.getElementById("user-info").innerHTML = ""; document.getElementById("latest-repo").innerHTML = ""; 느낀 점처음 user의 정보를 가져오는 BaseUrl을 찾는 것이 어려웠지만 url을 찾고 나니 나머지는 데이터 가공 뿐이라서 만드는 과정은 재밌었다. main 화면검색 결과 화면 (user info)검색 결과 화면 (latest repo)  <React 과제> Day 9 Mission (예산 계산기)github 주소 : https://github.com/noaprost/inflearn_react_mission_budget_calculator개발 시간 : 4시간구현 사항예산 목록을 생성, 수정, 삭제할 수 있어야 한다.목록 지우기 버튼을 누르면 목록 전체가 삭제되어야 한다.생성, 삭제, 수정 시 맨 위에 status를 알려주는 상태 메세지를 띄워준다.총 예산을 계산해서 가장 아래쪽에 표시해준다. 느낀 점그동안 Next.js, Three.js 공부를 하느라 React 프로젝트를 오랫만에 만들었더니 간단한 CRUD 앱인데도 꽤나 어렵게 구현하였다. 역시 꾸준한 것 보다 좋은 것은 없는 것 같다ㅠㅠ 과제를 진행하면서 잠시 잊었던 감을 다시 찾아야겠다는 생각이 들었다. main 화면예산 입력 후 화면예산 수정 화면  Day 10 Mission(디즈니 플러스 앱)github 주소 : https://github.com/noaprost/disneyplus_clone개발 기간 : 약 2일페이지 별 구현 사항로그인 페이지firebase를 이용해서 구글로 로그인을 한다.로그인 버튼을 누르면 popup창이 뜨고 로그인이 되면 홈으로 이동한다.Navbaruser가 있으면 프로필 사진이 원형으로 보여지고, 없으면 LOGIN 버튼이 보여진다.disney 로고를 누르면 user가 있을 경우 "/home"으로 이동, 없을 경우 "/"로 이동한다.user 프로필 사진을 hover하면 LOGOUT 버튼이 1.5초간 보여지고 클릭 시 user 정보가 사라진다.메인 페이지axios를 이용해서 영화 목록을 받아온 뒤 영화 하나의 정보를 보여준다. (이미지, 제목, 설명)영화사 버튼을 만들고, hover 시 영상이 재생되도록 한다.인기 영화, 평점 높은 영화, 판타지 영화, 액션 영화 각 카테고리에 맞는 영화들의 이미지를 보여준다.카테고리에 보여지는 영화들은 swiper를 이용해서 감싸준다.카테고리에 보여지는 영화를 클릭할 경우 상세 정보를 담은 모달이 나오고, 화면 밖을 클릭할 경우 모달이 닫히게 해준다.Modal이미지, 개봉일, 제목, 평점, 설명을 보여준다.메인 페이지에 오면 검색 창이 나타나고, 검색어 입력 시 검색 페이지로 이동한다.검색 페이지에서 메인 페이지로 돌아오게 되면 useLocation을 이용해서 검색어를 초기화해준다.검색 페이지로 이동할 때 검색어 정보를 query에 담아 url에 파라미터로 보내준다.검색 페이지useLocation으로 받은 데이터를 가공해서 검색어를 저장한다.검색어가 변경될 때마다 검색어를 query로 받는 검색 결과를 업데이트 해준다.결과의 이미지를 목록의 형태로 보여준다.이미지를 클릭할 경우 화면에 꽉 찬 이미지가 보여진다. 느낀 점이번 프로젝트를 하면서 React, CSS, Html, JS에 대해 새로운 것을 많이 알게 되었다. 과제를 하는 동안에는 에러도 많이 나고, 데이터가 안받아지거나, 페이지가 예상한대로 동작하지 않아서 스트레스도 많이 받아가며 만들었지만, 그 과정에서 실력은 확실히 성장할 수 있었다. 끝나고 나니까 뿌듯하고 계속 보게 됐다. 아쉬운 점카테고리 별로 영화 정보를 받아올 때, 인기 영화와 평점 높은 영화를 받아오는 api 주소와 장르별 영화를 받아오는 api 주소가 달라서 서로 다른 컴포넌트에서 로직을 짰다. 이것 때문에 swiper 코드와 Modal 코드, 목록을 보여주는 코드들이 중복이 된 것 같아서 아쉽다. 로그인 페이지메인 페이지메인 페이지 (영화사 버튼 hover 시)메인 페이지 (카테고리 별 목록)메인 페이지 (영화 상세 정보 모달)검색 페이지검색 페이지 (이미지 클릭 시)  Day 12 Mission (퀴즈 앱)github 주소 : https://github.com/noaprost/quiz_app개발 시간 : 3시간라우터 구조 및 구현 사항"/"Welcome to Quiz App을 보여준다."/question"수학 문제 2개를 보여준다.라디오 버튼을 클릭하면 답변 확인 버튼이 뜬다.답변 확인 버튼을 클릭하면 정답을 클릭했을 경우와 오답을 클릭했을 경우를 나눠서 보여준다.정답을 클릭했을 경우 border color를 green으로, 오답을 클릭했을 경우 red로 보여준다.정답인 label에 v표시를 붙여주고, 오답인 label에는 x를 붙여준다."/state"math와 alphabet 중에 하나를 선택할 수 있는 select box를 보여준다.선택하면 카테고리에 맞는 문제를 보여준다.채점 방식은 question과 동일하다."/quiz"퀴즈를 보기 전math와 alphabet 중에 하나를 선택할 수 있는 select box를 보여준다.연습 테스트 시작 버튼을 보여준다. 클릭하면 퀴즈 화면으로 변경된다.퀴즈를 보는 중문제와 남은 문제 수가 보여진다.답을 선택하면 다음 버튼이 보여지고, 마지막 문제였을 경우 제출 버튼이 보여진다.다음 버튼을 선택하면 다음 문제가 보여지고, 제출 버튼을 누르면 결과 화면으로 변경된다.퀴즈를 본 후총 문제 수 중 몇 문제를 맞췄는지 보여준다. (합격했을 경우 초록색, 아닌 경우 빨간색)시험 합격/불합격 여부가 보여진다. (4개 전부 맞을 경우 합격, 아닌 경우 불합격)새로운 연습 테스트 시작 버튼이 보여진다.버튼 클릭 시, 퀴즈를 보기 전 화면으로 돌아간다. 아쉬운 점문제를 랜덤으로 동적 생성하고 퀴즈의 문제 수도 설정할 수 있도록 구현해보고 싶었는데 시간이 부족해서 구현하지 못했다. 스터디가 끝난 후에라도 혼자서 개발해보고 싶다. 느낀 점그래도 가장 최근에 개발할 때 사용했던 Next.js와 Typescript여서 비교적 편하게 개발했던 것 같다. 구조들이나 변수가 반복되는 부분이 많다 보니 코드를 가독성 있게 짜기가 쉽지 않았다. 리팩토링에 대한 공부의 필요성이 느껴졌다. home 화면question 화면 (문제를 풀기 전)state 화면 (문제를 푼 후)quiz 화면quiz 화면 (연습 테스트 시작)quiz 화면 (테스트 결과) 

JSReact인프런스터디과제미션

하얀종이개발자

인프런 워밍업 클럽 2기 - CS 전공지식 스터디 특별미션

특별미션 특별 미션) 실수로 워밍업 클럽 출석을 빼먹었는데 우연히 데이터를 수정할 수 있는 권한이 주어졌습니다. 러너분의 이름(name)과 출석수(count)가 저장된 배열에서 여러분(나)의 데이터를 퀵정렬을 이용해 오름차순 정렬하고 가장 첫 번째 데이터인 여러분의 출석수를 변경하도록 코드를 작성해주세요. (퀵정렬 구현 부분도 변경) import java.util.Arrays; public class QuickSort { public static void main(String[] args) { User[] arr = { new User("홍길동", 5), new User("임꺽정", 4), new User("이순신", 3), new User("나", 1), new User("짱구", 5) }; System.out.println("===== 정렬 전 ====="); System.out.println(Arrays.toString(arr)); // 퀵정렬 실행 quickSort(arr, 0, arr.length - 1); // 첫 번째 나의 데이터의 출석수 변경 arr[0].count = 5; System.out.println("===== 정렬 후 ====="); System.out.println(Arrays.toString(arr)); } // 퀵정렬 함수 static void quickSort(User[] arr, int left, int right) { // 기저조건 if (left >= right) { return; } int pivotIndex = divide(arr, left, right); quickSort(arr, left, pivotIndex - 1); quickSort(arr, pivotIndex + 1, right); } // 배열을 나누고 피벗의 위치를 반환하는 함수 static int divide(User[] arr, int left, int right) { int pivot = arr[left].count; // 피벗은 첫 번째 원소의 count 값 int leftStartIndex = left + 1; int rightStartIndex = right; while (leftStartIndex <= rightStartIndex) { // 피벗보다 큰 값을 찾을 때까지 왼쪽에서 오른쪽으로 이동 while (leftStartIndex <= right && arr[leftStartIndex].count <= pivot) { leftStartIndex++; } // 피벗보다 작은 값을 찾을 때까지 오른쪽에서 왼쪽으로 이동 while (rightStartIndex >= left + 1 && arr[rightStartIndex].count >= pivot) { rightStartIndex--; } // 인덱스가 교차하지 않았으면 값 교환 if (leftStartIndex < rightStartIndex) { swap(arr, leftStartIndex, rightStartIndex); } } // 피벗과 rightStartIndex 교환 swap(arr, left, rightStartIndex); return rightStartIndex; } // 두 원소의 값을 교환하는 함수 static void swap(User[] arr, int index1, int index2) { User temp = arr[index1]; arr[index1] = arr[index2]; arr[index2] = temp; } } class User { String name; int count; User(String name, int count) { this.name = name; this.count = count; } @Override public String toString() { return "{name: '" + name + "', count: " + count + "}"; } }  문제를 해결하기 위한 퀵정렬을 수행하고 나의 출석수를 변경하는 코드를 Java로 작성했습니다.count 기준으로 정렬하고, 정렬된 배열의 첫 번째 데이터인 나의 출석수를 5로 변경하는 로직입니다.개인 일정때문에 첫번째 OT를 빠졌었는데, 구제될 수 있는 기회가 생겼네요.감사합니다.!!

백엔드인프런워밍업클럽2기CS전공지식특별미션

운영체제

*이 내용은 인프런 그림으로 쉽게 배우는 운영체제를 수강하며 정리한 내용입니다. program과 process하드디스크등과 같은 저장장치에 저장된 명령문의 집합체를 말해.애플리케이션이나 앱이라고도 불리고 windows 운영체제에서는 .exe 의 모습을 하고있지.그럼 process는 뭘까?간단히 말하면 실행중인 프로그램이야.하드디스크에 저장된 프로그램이 메모리에 올라갔을 때 실행 중인 프로그램, 즉 프로세스라고 불려.프로그램은 수동적, 프로세스는 수동적인 존재라고 할 수 있어. process의 구조CodeDataHeap : 프로그래머가 동적으로 메모리를 할당하는데에 쓰인다. ( malloc, free )Stack컴파일 과정멀티프로그래밍과 멀티프로세싱유니프로그래밍 : 메모리에 오직 하나의 프로세스가 올라온 것 멀티프로그래밍 : 메모리에 여러 개의 프로세스가 올라온 것   멀티프로세싱 :  CPU가 여러 개의 프로세스를 처리하는 것PCB (Process Control Block)프로세스가 만들어지면 운영체제는 해당 프로세스의 정보를 가지고있는 PCB를 만들고 저장해.PCB들은 연결리스트라는 자료구조로 저장돼.운영체제는 프로세스가 종료되면 해당 프로세스의 PCB를 연결리스트에서 제거해.프로세스 상태실행상태에 있는 프로세스의수는 CPU의 개수만큼 입니다.대기상태프로세스가 입출력 요청을 하면 입출력이 완료될 때까지 기다리는 상태야.CPU에 비해 입출력작업은 상당히 느려.특정 프로세스가 입출력 요청을 하면 입출력이 완료될 때까지 CPU를 기다리게 하는건 굉장히 비효율적이야.대신 입출력 요청을 한 프로세스를 "대기상태"로 두고 다른 프로세스에게 CPU를 할당해그러다가 시간이 지나서 입출력 작업이 완료되면 "대기상태"에 있던 프로세스에게 CPU 할당 기회를 줘 컨텍스트 스위칭프로세스를 실행하는 중에 다른 프로세스를 실행하기 위해 실행중인 프로세스의 상태를 저장하고 다른 프로세스의 상태값으로 변경하는 작업이야.컨텍스트 스위칭이 일어날 때 PCB의 내용이 변경돼. 실행 중인 프로세스의 작업 내용을 PCB에 저장하고 실행될 기존 프로세스의 PCB의 내용대로 CPU가 다시 세팅돼.컨텍스트 스위칭이 일어날 때 PCB에 변경하는 값들로는 아래와 같아.운영체제에서 프로세스 A와 프로세스 B사 컨텍스트 스위칭을 하는 법을 알려줄게.먼저 CPU에서 프로세스 A를 실행해.시간이 지난 후 운영체제에서 CPU가 프로세스 A를 너무 오래 실행했다고 판단하면프로세스 A는 하던 일을 멈추고, 현재 CPU의 레지스터 값 등을 PCB A에 저장해.이제 PCB B를 참조해서 이전 프로세스 B의 상태로 CPU의 레지스터값을 설정해.여기에는 다음 실행할 명령어의 주소를 가지고있는 프로그램 카운터(PC)를 가지고있기 때문에 바로 프로세스 B의 명령어를 실행할 수 있어.프로세스 B가 점유시간동안 CPU를 사용하다가 점유시간이 다되면 운영체제는 다시 인터럽트를 발생시키는거지. 컨텍스트 스위칭은 CPU 점유시간이 다됐거나, I/O 요청이 발생하거나, 다른 종류의 인터럽트가 있을 때 등의 상황에서 발생해. 프로세스 생성과 종료일반적으로 프로세스가 생성될 때의 방법에 대해 설명할게..exe 파일을 더블클릭으로 실행하면 운영체제는 해당 프로그램의 코드영역과 데이터영역을 메모리에 로드하고 빈 스택과 빈 힙을 만들어 공간을 확보해.그리곤 이 프로세스를 관리하기 위한 PCB를 만들어서 값을 초기화해줘.지금 설명한 프로세스 생성과정은 운영체제가 부팅되고 0번 프로세스가 생성될 떄 딱 한번 실행돼.그리고나서 나머지 모든 프로세스는 새로 생성하지않고 0번 프로세스를 복사해서 사용하게 돼.이때 fork() 함수를 사용해.복사해서 사용하는 이유는 새로 생성하는 것보다 복사를 하는게 더 빠르기 때문이야.0번 프로세스를 복사해서 생성된 프로세스들을 자식 프로세스라고 해. 그럼 0번 프로세스는 부모 프로세스가 되겠지?자식 프로세스는 부모 프로세스의 코드영역, 데이터영역, 스택영역과 PCB의 내용을 전부 복사해.0번 프로세스의 코드와 데이터를 모두 복사해서 실행하면 0번 프로세스가 똑같이 실행되는거 아닌가?맞아...그럼 자기가 원하는 함수를 어떻게 실행시킬까? 바로 exec() 함수를 이용하면 돼.fork() 함수로 프로세스를 복사 후 exec() 함수를 실행시키면 자식 프로세스의 코드와 데이터 영역을 원하는 값으로 덮어쓰게 돼.그럼 이때부터 자식 프로세스는 부모 프로세스와 완전히 다르게 동작하게되는거지!쓰레드   참조 : 그림으로 쉽게 배우는 운영체제 3주차 회고칭찬하고 싶은 점 : 기한을 지켰다 😅아쉬웠던 점 : 권장 커리큘럼을 지키지 못했다.

운영체제워밍업클럽CS

예진안

인프런 워밍업 클럽 스터디 2기 - CS 전공지식<10월 셋째주 발자국> +미션

⭐ 발자국운영체제가상메모리가상메모리와 가상메모리를 효율적으로 사용하는 방법!- 세그멘테이션 & 페이징 => 요즘엔 페이징과 페이지드 세그멘테이션 자주사용페이지 교체정책 : FIFO, LRU, 옵티멈, 클락 알고리즘, FIFO의 2차 기회 교체 알고리즘스레싱과 워킹셋 모두 pagefault를 줄여서 cpu 사용률이 떨어지는 것을 막음! 입출력 장치주변장치들 메인 보드 내의 버스로 연결(시스템버스, 입출력제어기,DMA ..)하드디스크(헤드, 플레터, 실린더,트렉,섹터..) 읽어오는 방법파일시스템 -> 위에서 공부한 메모리와 비슷하다 - 순차 파일 구조, 집적파일구조- 파일의 파일 디렉토리 알고리즘정렬 : 버블정렬, 선택정렬, 삽입정렬 모두 간단하지만 성능이 뛰어나진 않음병합정렬, 퀵정렬 모두 앞서 말한 정렬보다 성능이 뛰어나다.동적 프로그래밍 : 메모이제이션(재귀), 티뷸레이션(상향식 계산방식) ⭐ 미션운영체제1. 메모리의 종류는 어떤것들이 있나요? 각 메모리의 특징도 함께 적어주세요.cpu안에 있는 레지스터, 캐시메모리가 있다. 그리고 메인 메모리인 RAM 과 보조저장 장치가 존재한다.빠르고, 용량작고, 가격비쌈 ---> 느리지만,용량크고, 가격합리적!레지스터, 캐시메모리, RAM, 보조저장장치레지스터 : cpu와 가장 가까운 메모리이다. 휘발성 메모리를 가지고 있어 직접적으로 프로그램을 작업하기 어렵다.cpu가 연산처리를 할 때 RAM에 있는 정보를 가져와 레지스터에서 연산하고 결과를 RAM에 저장해둔다.캐시 메모리 : 너무 빠른 레지스터와 그에 비해 너무 느린 RAM을 이어주는 메모리.RAM이 직접 레지스터에 데이터를 올리기엔 너무 느리기 때문에레지스터가 필요할 것 같은 RAM에 있는 데이터를 캐시메모리에 올려놓는다.캐시 메모리는 여러개 있을 수 있다~!메인메모리 : 실제로 프로세스들이 올라가서 작업하는 메모리 공간이다.휘발성 메모리라 데이터를 저장하는 공간이기 보다는 운영체제, 프로세스들을 올리는 공간이다.보조저장장치 : 다른 메모리들과 다르게 휘발성이 아니면서 용량은 크고 가격은 합리적인 메모리. 2. 사용자 프로세스가 메모리의 운영체제 영역에 침범하지 못하도록 만든 레지스터는 어떤 레지스터일까요?경계 레지스터이다. 메모리관리자가 프로세스가 경계 레지스터 값을 벗어났는지 검사한다. 벗어났을 경우 헤당 프로세스를 종료시킨다.3. 메모리 할당 방식에서 가변 분할 방식과 고정 분할 방식의 장단점은 뭔가요?가변분할 방식에서는 프로세스 크기에 맞게 메모리를 순서대로 할당 시킬 수있다. 연속적으로 메모리를 할당시켜서 내부단편화가 없다. 하지만 외부단편화가 생긴다.외부단편화란, 외부단편화는 메모리크기 100에 프로세스 a,b,c가 20,30,40씩 메모리를 할당하고 있었다. 프로세스b가 먼저 작업이 끝나 메모리를 떠났고 40크기의 새로운 프로세스d가 작업을 해야한다. 메모리에는 사용가능한 공간이 총 40이지만 연속적으로 비어 있지 않기 때문에 40짜리 프로세스는 들어갈 수 없게 된다.프로세스들을 끌어와서 빈공간이 연속적이게 만들 수있지만 오버헤드가 커지기 때문에 추천하지 않는다.고정 분할 방식에서는 정해진 크기로 메모리를 분할하고 프로세스는 크기에 맞게 할당된다. 외부단편화는 생기지 않지만 내부 단편화가 생긴다.내부단편화란, 정해진 크기로 프로세스가 할당되고 정해진 크기로 분할한 메모리에 빈공간이 남는 현상이다. 버디 시스템을 이용해서 메모리를 얼만큼 분할할지 어떤 크기에 어떤프로세스를 할당할지 선택할 수있어서 내부단편화를 줄일 수있다.4. CPU 사용률을 올리기 위해 멀티프로그래밍을 올렸지만 스왑이 더 많이 이루어져 CPU 사용률이 0%에 가까워 지는 것을 뭐라고 할까요?스레싱이라고 한다. 물리적인 메모리의 크기가 작은 것이 원인이다. 메모리의 크기를 늘ㄹ려 스레싱을 없애 성능을 향상시킬 수 있다. 하지만 메모리가 클수록 좋은 것은 아니다. 만약 4GB에서 스레싱이 일어나지 않았다면 4GB일 때 스레싱이 일어나기엔 충분한 메모리의 크기이다. 굳이 큰 메모리로 바꿀 필요가 없다는 것이다. 16GB로 바꾼다고 4GB보다 성능향상이 일어나는 게 아니고 똑같다!5. HDD나 SSD는 컴퓨터를 실행시키는데 꼭 필요한 걸까요?이유를 함께 적어주세요. 6. 파일을 삭제해도 포렌식으로 파일을 복구할 수 있는 이유가 무엇일까요?파일 전체를 다 지우는 것이 아니다. 파일 테이블의 헤더를 삭제하고 프리블록 리스트에 추가하게된다. 그렇게 되기때문에 삭제하고자 하는 데이터는 그대로 남아있기 때문에 파일을 리스트에서 불러와서 복구가 가능하다.자료구조와 알고리즘1. 지금까지 배운 5개의 정렬 알고리즘의 장단점과 시간 복잡도를 적어주세요.버블 정렬, 선택정렬, 삽입정렬 모두 O(n제곱) -> 구현이 쉽지만 효율이 떨어진다.병합 정렬 O(n*logn) -> 재귀식을 사용해서 구현이 어렵지 효율up퀵정렬 (세타 n logn)-> 다른 정렬알고리즘에 비해 가장 불균형이 없을 경우 빠르다. 정렬된 리스트에서는 불균형때문에 오히려 수행시간이 더 걸릴 수가 있다. 다른 정렬에 비해 메모리사용도 적고 데이터간의 비교도 적기 때문에 효율성이 좋다.2. 메모리가 부족한 시스템에서 어떤 문제를 해결하는데 재귀로 쉽게 구현이 가능할 것 같습니다.여러분이라면 메모이제이션과 타뷸레이션 중 어떤 걸 이용하실 건가요? 이유를 함께 적어주세요.메모이제이션을 사용해서 구현할 것 같다.이전에 계산한 값을 메모리에 저장하기 때문에 중복적인 계산을 한 데이터를 지우며 전체적으로 실행 속도를 빠르게 해주기 때문에 메모리가 부족한 시스템에서 해결할 때 필요할 것같다.회고윽.. 너무 늦게 내버렸다. 이번주 목표가 하루하루 계획한 날짜에 수업들으면서 복습하는 거였다.. 이번주는 나자신에게 졌다.. 이긴쪽도 나니까 내가 이긴 거일지도. ^^~여유롭게 복습하고 내고싶었는데 쫓기듯 수업을 듣게되어서 제대로 복습한 느낌도 별로 들지 않았다..... 이거 회고내고 내일 복습 다시하려고한다. 그래도 이해가안되면 다시 동영상듣고 복습하다보니까 자연스럽게 스토리(?)가 떠올라서 이 방식으로 공부하는 거. 나쁘지 않을지도

대협

[인프런 워밍업 클럽 2기 - BE] 1주차 발자국

이 블로그는 정보근님의 입문자를 위한 Spring Boot with Kotlin - 나만의 포트폴리오 사이트 만들기 강의 기반으로 코드작성과 코드설명을 적었습니다 나의 첫 인프런 블로그가 이렇게 쓰여질 줄은 몰랐다.. 그동안 인프런 강의들을 많이 애용했지만, 이렇게 블로그를 작성하지는 않아서 낯설기도 하고, 설레기도 한다.발자국 내용은 딱히 형식이 정해져 있지 않아서 발자국 쓰기 전날까지 들었던 강의들 중, 모르는 내용들을 적어서 내가 다시 봤을 때, "아 맞다!" 라는 말이 나올 정도로만 적을 예정이다! 목차모르는 내용 정리 미션 해결 과정회고   1. 모르는 내용 정리 <Gradle>Gradle : Gradle은 Groovy를 기반한 빌드 관리 도구.빌드 관리 도구 : 프로젝트 내에서 다양하게 외부 라이브러리와 로컬 레포지토리에서도 라이브러리 별로 버전 관리를 해야할 때 용이Gradle이 왜 필요할까?Gradle과 Maven 차이를 알면 Gradle이 왜 필요한지 알 수 있다.Gradlegroovy 언어를 사용한 Domain-specific-language를 사용 ( 코드가 간결)어느 task가 업데이트 되었는지 체크이미 반영된 빌드 부분은 더이상 재 실행되지 않는다. -> 빌드 시간 단축Mavenjava8용 프로젝트 관리 도구 apache의 ant 대안외부 저장소에서 필요한 라이브러리, 플러그인들을 다운로드 한 후 , 로컬 시스템의 캐시에 모두 저장그래서 왜 Gradle인데!!!Gradle은 작업 의존성을 그래프, Maven은 고정적이고 선형적 모델을 기반Gralde은 어떤 task가 업데이트되었고 안되었는지를 체크Gradle은 이미 업데이트 된 task에 대해서는 작업이 실행되지 않으므로 빌드 시간 단축빌드 설정 규모가 작으면 큰 차이를 느끼지 못하지만 규모가 크면 훨씬 Gradle의 빌드 시간이 단축된다는걸 알 수 있다. <Dependencies>Spring Web : 웹 어플리케이션을 개발하기 위한 핵심 기능 제공Thymeleaf : View Template, 동적으로 화면을 구성할 수 있게 해줌Spring Data JPA : JPA를 이요한 구현체를 더 추상화시켜 더 쉽고 간편하게 JPA를 이용 가능mysql driver : mysql를 연동할 때 필요한 dependencyh2 database : RDBMS, 테스트 단계 또는 작은 규모의 프로젝트에서 사용validation : 데이터에 대한 유효성 검증 처리를 수행Spring Security : 홈페이지에 인증 및 권한 기능을 빠르게 부여해 인증 및 권한 보호 기능을 손쉽게 추가할 수 있음. <프로그램이 시작되는 시작되는 코드>src/main/kotlin/PortfolioApplicatioin.ktfun main(args: Array<String>) { runApplication<PortfolioApplication>(*args) } Whitelabel Error Page 오류가 뜨는 이유 : 어플리케이션이 뭘 해야 할지 모르기 때문에 Whitelabel Error Page를 보내줌.(정상) <Git 용어>Git : 분산 버전 관리 시스템 ⇒ 협업을 쉽게 해주는 툴 : GitHubCommit : git에 저장하는 단계Rollback : 이력 되돌리기Branch : branch 생성 및 제거, 확인등의 기능을 하는 명령어Merge : 브랜치 병합Conflict : 충돌Repository : 원격 저장소 , 인터넷이나 네트워크 어딘가에 있는 저장소Push : 로컬 브랜치를 원격 저장소로 푸시할 때 사용하는 기본 명령어 <Git 명령어>git init : git 공간으로 초기화git status 명령어 입력시 Untracked files 라는 게 있는데 이건 git에서 따로 설정을 안한다는 소리https://www.toptal.com/developers/gitignore/ : gitignore 파일을 자동으로 만들어줌 <github에 PUSH 방법>터미널에서 git initgit remote “git 저장소”→ 인텔리제이(GUI)로 할 시에는 git → Manage Remotecommitpush <application-default.yml , application-docker.yml>profile이 default 이면, application-default.yml 파일에서 환경변수를 가져오고profile이 docker 이면, application-docker.yml 파일에서 환경변수를 가져온다. application-default.yml 파일에서 spring:jpa:hibernate:ddl-auto:create 인데왜 application-docker.yml 파일에서는 spring:jpa:hibernamte:ddl-auto:none 일까?=> application-default.yml 에서는 개발 목적으로 데이터베이스 스키마를 매번 재생성할 필요가 있지만, application-docker.yml 에서는 베포 및 운영 환경에 적합하게 데이터베이스 구조가 변경되지 않도록 하기 위한 설정 <어노테이션 정리>@Id : 해당 테이블의 PK 필드를 의미@Entity : JPA를 사용해 테이블과 매핑할 클래스에 붙여주는 어노테이션@GeneratedValue : JPA에서 Entity의 PK를 생성하여 주는 기능-> @GeneratedValue(name="member_id") : PK로 사용될 Entity의 프로퍼티에 @Id 어노테이션 선언-> @GeneratedValue(strategy=GenerationType.IDENTITY) : 기본 키 생성을 데이터베이스에 위임한다.-> @GeneratedValue(strategy=GenerationType.AUTO) : 기본값으로 DB 방언에 맞춰 자동으로 설정하여 준다.@Column : 객체 필드와 DB 테이블 칼럼을 맵핑한다.@Component : 클래스를 자동으로 빈으로 등록하기 위해 클래스 레벨에서 사용@Profile : 빈이나, 컴퓨넌트에게 프로필을 정해줄 수 있음@PostConstruct : 객체의 생성이 일어난 직 후에 초기화를 수행하는 메서드에 부착한다.@ManyToOne : 단방향 관계이고 FK관리에 있어서 가장 자연스럽다. @JoinColumn 어노테이션과 같이 쓰인다.@JoinColumn : 엔티티 테이블에 FK 칼럼을 정의해준다. 자료형뒤에 ? 는 무슨 의미일까 ?ex ) Long?자료형 뒤에 ? 가 오는 것은 Kotlin에서 사용되는 문법이고 ?를 자료형 뒤에 붙이는 방식은 nullable 여부를 나타낸다. 예를 들면 var name: String? = null 이 코드는 해당 변수 name에 null 값이 올 수도 있다는 뜻이다.  <코드 분석>var type: SkillType = SkillType.valueOf(type) : SkillType.valueOf(type) 은 type이라는 문자열을 SkillType 열거형의 값으로 변환. 만약 type이 열거형에 없는 값이면 예외 발생var cookies: String? = httpServletRequest.cookies ?.map {"${it.name}:${it.value}"} ?.toString() : httpServletRequest에서 쿠키 정보를 가져오고, 쿠키 이름과 값을 "이름:값" 형식으로 변환하는 코드var referer: String? = httpServletRequest.getHeader("referer") : HTTP 요청에서 "Referer" 헤더 값을 가져온다. 이 코드는 사용자가 어떤 페이지에서 현재 페이지로 이동했는지 나타냄@OneToManyvar details: MutableList<ExperienceDetail> = mutableListOf() : JPA 관계를 나타내고, 엔티티 간의 일대다(One-to-Many) 관계를 나타냄2. 미션미션 1과 2를 제출하는건데, 미션1은 테이블 설계하기와 깃허브 리포지토리에 프로젝트 올리기이다. 미션 1 : https://github.com/HyupTech/LMS/commit/fa47b404d36b3ce418f16213e3bb30ca96b812ed미션 2 : https://github.com/HyupTech/LMS/commit/0993897036a0e17e7a366031b950235edd5d506e   3. 회고발자국을 작성하면서 나는 이제까지 강의를 보면서 공부를 했지만 다시 한번 이렇게 정리를 해가면서 강의를 보지 않았다. 왜냐하면 시간이 너무 아까웠고, 차라리 정리하는 시간에 강의를 하나 더 보자는 마인드였다. 하지만 발자국을 써보면서 왜 이렇게 좋은걸 내가 안했을까라는 후회가 들고, 이렇게 정리를 해가면서 했으면 아마 실력이 조금이라도 더 올랐지 않았나 라는 생각이 들었다. 앞으로 발자국도 쓰고, 내가 따로 공부하고 있는것도 정리해가면서 공부를 해야겠다. 3-1. 미션 회고 이번 미션에서 처음으로 ERD를 구성하고 어디에 PK를 주고 관계 설정을 어떻게 할지에 대한 고민이 많았던 것 같다. 현재 대학교 2-2에 재학중인데 데이터베이스 과목을 수강중인데 꽤 도움이 되었던 것 같고, 백엔드 개발자가 될려면 데이터베이스 공부도 놓지 말아야겠다고 생각이 들었다. 앞으로 더 많은 미션들이 기다리고 있는데 열심히 공부를 해야겠다!   

백엔드인프런워밍업클럽백엔드발자국javakotlin

초동

[인프런 워밍업 클럽 CS 2기] 3주차 발자국

학습기간1주차 2024-10-14(월) ~ 2024-10-18(금)강의 수강학습내용 요약알고리즘섹션3-알고리즘삽입 정렬(Insertion Sort)<aside>선택정렬과 마찬가지로 배열을 두 영역으로 나누어 정렬을 진행함 (정렬된 영역, 정렬되지 않은 영역)정렬되지않은 영역에서 데이터를 하나씩 꺼내서 정렬영역의 적절한 위치에 삽입하여 정렬하는 것 삽입 정렬의 성능도 버블,선택정렬과 같이 O(n^2)이다.병합 정렬(Merge Sort)<aside>반으로 나누고 또 반으로 나눠서 각 원소로 정렬 한 후 한단계 씩 병합해가면서 정렬재귀함수 호출 모양과 아주 비슷한 모양을 하고 있음 분할된 배열을 병합할때는 N개의 데이터를 n번 비교하므로 n과 logn을 곱해서 O(nlogn)의 성능이 나옴장점 : 성능이 지금까지 배운 정렬보다 좋음단점 : 재귀적인 기법을 이용해 이해와 구현이 어려움퀵 정렬(Quick Sort)<aside>퀵정렬은 이전에 알아본 병합정렬과 같이 분할 정복 알고리즘에 속함그래서 재귀를 사용함퀵정렬은 정렬전 배열에 있는 수자중 하나를 피벗 으로 설정해줌피벗을 선택하는 방법은 여러가지 있으나, 여기서는 이해하기 쉽게 배열의 왼쪽에 있는 것으로 선택함퀵정렬은 이렇게 한번 진행될 때 마다 피벗이 정렬되고 정렬된 배열을 좌우로 나눠 같은 방식으로 재귀호출해 모든 배열을 정렬함성능 피벗이 배열을 반으로 가르지않고 한쪽에 치우쳤을 경우 O(n^2)의 성능임대부분 피벗을 중간값으로 설정하므로 배열을 매번 반으로 가를 수 있어서 평균적인 성능은 ‘새타(nlogn)’의 성능을 가짐성능만 보면 병합정렬이 더 좋다고 볼 수 있는데, 실제로 병합정렬과 비교하면 퀵정렬이 더 적은비교와 더 적은메모리 공간을 차지하기 때문에 더 좋은 알고리즘으로 평가됨퀵정렬 : 새타(nlogn), O(n^2)병합정렬 : O(nlogn)장점 : 성능이 지금까지 배운 정렬보다 좋음단점 : 재귀적인 기법을 이용해 이해와 구현이 어려움 </aside>동적 프로그래밍-메모이제이션(memoization)<aside>재귀를 이용해 큰문제를 작은문제로 분할해서 해결했음 ⇒ 분할정복단점 : 재귀를 사용하면 함수가 호출되어 콜스택의 영역을 차지하는 단점 외에도 성능에 크게 영향을 미치는 단점이 있음피보나치 수열(하향식 문제)무한대 수열을 만듦….구현 시 성능이 좋지 못함return 값인 fibonacci(n-2)가 재귀적으로 호출할 때 반복계산이 되는 경우가 있고, 중복호출도 있음, 시간이 낭비됨⇒ 결과값을 저장해 함수호출수를 줄이고 성능이 향상됨메모이제이션으로 성능향상해보기계산하려는 데이터가 있는지 검색없다면 함수를 호출해 그결과를 저장⇒ 해시테이블(데이터 검색,삽입이 빠른 장점이 있음)을 이용⇒ 해시테이블의 키에 계산하려는 값을, 밸류에 계산결과를 저장함메모이제이션계산결과를 저장해서 여러번 계산하지 않도록 하는 기법장점 : 재귀적인 기법으로 어려운 문제를 단순히 풀 수 있고, 계산결과를 해시테이블에 저장하기 때문에 중복계산을 하지않아 속도가 빠름, 재귀가 더 직관적이라면 메모이제이션이 유리함단점 : 함수를 여러번 호출하는 재귀를 사용하기 때문에 함수를 하나 호출하는것보다 오버헤드가 더 들고, 함수호출로 메모리 공간에 스택을 차지하고 메모이제이션을 위한 해시테이블 공간까지 차지하기 때문에 메모리를 더 많이 사용함 </aside>동적 프로그래밍-타뷸레이션<aside>상향식 계산방식계산에 필요한 모든 값을 전부 계산후 테이블에 저장해둠재귀가 직관적이지 않을때는 타뷸레이션을 이용해 메모리도 절약하고 속도도 빠르게 해결할 수 있음 </aside>운영체제섹션8-가상메모리가상메모리 개요<aside>운영체제나 프로세스보다 큰 프로그램이 실행되지 못할 때, 가상메모리를 이용해 실행 할 수 있음프로세스(사용자)는 메모리 관리자(가상메모리)를 통해서 메모리(메인메모리)에 접근함프로세스 입장에서는 물리메모리에 직접 접근할일이 없고, 메모리 관리자에게 요청만 하면됨메모리 관리자는 프로세스의 요청이 있으면 그에맞는 물리 메모리로 연결시켜줌가상메모리의 크기는 이론적으론 무한대지만, 실제론 메모리의 크기와 CPU의 비트수로 결정됨ex) 만약 32비트의 경우, 표현할 수 있는 주소값은 2^32승으로 대략 4GB정도 되고, 가상 메모리의 크기도 똑같이 4GB임가상메모리 할당운영체제가 사용하는 0번지를 제외가상메모리 시스템에서는 운영체제 영역을 제외한 나머지영역을 일정한 크기로 나누어서 프로세스에게 할당함메모리 분할방식과 동일하게 가변분할방식(세그멘테이션)과 고정분할방식(페이징)으로 나뉨각각 단점을 보완한 세그멘테이션-페이징 혼용기법을 사용함가상메모리시스템-가상주소가상주소는 메모리나 스왑영역 중 한 곳에 위치함메모리 관리자는 가상주소와 물리주소를 일대일 매핑 테이블로 관리함 동적 주소 변환(DAT, Dynamic Address Translation)메모리 관리자는 물리메모리+스왑영역을 합쳐서 프로세스가 사용하는 가상주소를 물리주소로 변환함동적주소변환을 거치면 프로세스는 마음대로 사용자 데이터를 물리 메모리에 배치할 수 있음 </aside>세그멘테이션(배치정책)<aside>세그멘테이션에서 프로그램은 함수나 모듈등으로 세그먼트를 구성함데이터, 코드, 힙, 스택, 라이브러리 등 장점 : 메모리를 가변적으로 분할 할 수 있고,각 영역을 모듈로 처리할 수 있기 때문에 공유와 각 영역에 대한 메모리 접근보호가 편리함단점 : 가변분할 방식의 단점인 외부단편화가 발생함논리주소사용자, 프로세스, CPU가 바라보는 주소메모리 관리자(MMU)가 중간에서 세그멘테이션 테이블에 저장된 Base Address와 Bound Address 정보를 이용해 물리주소로 변환 해줌CPU에서 논리주소가 전달되면, 메모리관리자는 이 논리주소가 몇번 세그먼트인지 알아내서 메모리관리자 내의 segment table base register에서 물리 매모리내에 있는 세그멘테이션 테이블을 찾고 세그먼트 번호를 인덱스로, base address와 bound address를 찾음cf) 운영체제는 컨텍스트 스위칭을 할 때 마다 메모리 관리자 내에 있는 segment table base register를 해당 프로세스의 것으로 값을 바꿔줘야 하기 때문에 컨텍스트 스위칭은 굉장히 무거운 동작임 논리주소 → 물리주소 변환 예시CPU에서 세그먼트 1번이 0x632번지로 접근한다고 가정해보자메모리 관리자는 CPU의 요청을 받고 세그먼트가 1번인 것을 알아내고, 메모리 관리자 내에 있는 segment table base register를 이용해서 세그멘테이션 테이블을 찾아냄세그멘테이션 테이블을 찾은다음, 세그먼트 1번이 위치한 1번 인덱스를 참조하고, 논리주소 632와 bound address 1000을 비교해보면 논리주소가 더 작음⇒ 더 작은 논리주소 632와 base address 5200을 더해 물리주소 5832가 됨</aside>페이징(배치정책)<aside>메모리를 할당할 때 정해진 크기의 페이지로 나눔모든 페이지는 크기가 같기때문에 관리가 쉬워지고, 외부단편화 현상이 발생하지 않음물리주소 공간도 논리주소공간(페이지)과 같이 동일하게 나뉘는데 이걸 프레임 이라고 부름페이징의 주소변환 방법세그멘테이션과 마찬가지로 메모리관리자는 테이블을 갖고 있고, 이를 페이지 테이블 이라고 부름CPU에서 논리주소를 전달해주면, 메모리 관리자는 이 논리주소가 몇번 페이지 인지, 오프셋은 얼마인지 알아냄메모리 관리자 내 page table base register(PTBR)를 이용해서 물리 메모리에 있는 페이지 테이블을 찾고, 페이지 번호를 인덱스로 프레임 번호를 알아내고 오프셋을 이용해 물리주소로 변환함오프셋의 계산페이지 테이블에 invalid로 표시되어있으면 스왑영역, 즉 하드디스크에 저장되어 있다는 의미임세그멘테이션과 페이징의 차이페이지의 크기이다.세그멘테이션은 프로세스마다 크기가 달라 bound address를 가지고 있지만,페이징은 모든 페이지의 크기가 동일해서 크기를 표현하는 bound address는 필요하지 않음세그멘테이션 (외부단편화 발생), 페이징 (내부단편화 발생-정해진 크기의 페이징보다 프로세스의 정보가 작으면 그만큼 공간이 낭비됨)페이징은 페이지의 크기가 고정되어있기때문에 공유하거나 권한을 부여하는게 어려움페이징에서 가장 신경써야하는것은 페이지 테이블의 크기임각 프로세스마다 페이지 테이블을 가지고 있는데, 프로세스가 많아질수록 테이블도 많아지기 대문에 프로세스가 실제로 사용할 수 있는 메모리 영역이 줄어듦실제로 메모리 관리자가 참조하는 페이지 테이블도, 물리메모리의 운영체제 영역에 저장되어 있기 때문에 페이지 테이블의 크기가 너무 크면 사용자 영역이 부족하게 됨 </aside>페이지드 세그멘테이션(배치정책)<aside>세그멘테이션과 페이징의 장점을 취한 방식메모리 접근권한은 메모리의 특정 번지에 부여된 권한으로 읽기(Read), 쓰기(Write), 실행(Execute) 3가지로 나뉨ex) 0x0 ~ 0x1000까지는 읽기 권한, 0x1000~0x2000까지는 읽기,쓰기 권한 설정 .ᐟ프로세스의 각 영역의 메모리 권한 알아보기CODE : 프로그램 그 자체이므로 수정되면 안됨 → 읽기/실행 권한DATA : 일반변수, 전역변수, 상수로 선언한 변수 저장 → 읽기 /(쓰기)권한HEAP : 읽기/쓰기 권한STACK : 읽기/쓰기 권한메모리 접근 권한 검사가상주소→물리주소 변환 될 때마다 일어남권한 위반 시 에러발생 및 종료페이지드 세그멘테이션세그멘테이션 테이블과 페이지 테이블이 혼합된 것세그멘테이션 테이블에는 권한 비트를 추가하고, base address는 페이지 넘버로 바뀌고, bound address는 이 세그멘트의 페이지 개수로 바뀜(이름만 달라졌을 뿐 본질은 달라지지 않음)단점 : 물리메모리에 접근하기 위해서 메모리에 접근을 2번 해야됨(1. 세그멘테이션 테이블 참조, 2.페이지 테이블 참조)⇒ 오늘날에는 이러한 단점때문에 페이징과 페이지드 세그먼테이션 기법을 적절히 섞어서 사용함</aside>디맨드 페이징(가져오기 정책) 조만간 필요할 것 같은 데이터를 메모리로 가져오고, 쓰이지 않을 것 같은 데이터는 스왑영역으로 이동시키는 정책임스왑영역으로 데이터를 이동시키는 것을 최소화 시켜야 함(CPU의 수백개가 넘는 사이클이 걸리기 때문에 성능이 안좋아짐)페이지 테이블을 이루고 있는 한 행을 페이지 테이블 엔트리(PTE) 라고 함페이지 테이블 엔트리(PTE)접근비트페이지가 메모리에 올라온 후 데이터에 접근이 있었는지 알려줌메모리에 읽기나 실행 작업을 했다면 1 로 바뀜변경비트페이지가 메모리에 올라온 후 데이터에 변경이 있었는지 알려줌메모리에 쓰기 작업을 했다면 1 로 바뀜유효비트페이지가 물리메모리에 있는지 알려줌유효비트가 1이라면 스왑영역에 있고, 0이라면 물리메모리에 있음읽기/쓰기/실행 비트해당 메모리에 접근권한이 있는지 검사하는 권한비트 페이지 교체정책<aside>프로세스는 데이터 접근을 위해 메모리를 참조하는데, 해당 데이터가 메모리에 없으면 Page Fault가 발생함Page Fault가 발생하면 해당 페이지를 스왑영역에서 메모리로 불러들여야하는데 메모리가 꽉차서 공간이 없다면 메모리에 있는 페이지 중 하나를 선택헤서 스왑영역으로 옮겨야 함메모리에 있는 페이지를 스왑영역으로 옮길때 어떤 페이지를 선택할지 결정하는 정책을 페이지 교체정책이라고 함페이지 교체정책의 종류무작위 선택 방법무작위로 선택해서 교체하는 이 방법은 지역성을 고려하지 않기때문에 자주사용되는 페이지가 선택될 수 있어 성능이 별로 좋지 않음그래서 거의 사용되지 않음FIFO(First In First Out, 메모리에 들어온지 가장오래된 페이지를 선택하는 방법)페이지 1이 먼저 들어왔으면 먼저 교체함단점 : 자주쓰는 페이지가 먼제 교체되는 단점이 있음구현이 간단하고 성능도 꽤 괜찮아서 조금 변형해서 많이 쓰임Optimum(앞으로 가장 오랫동안 쓰이지 않을 페이지를 선택하는 방법)사실상 구현이 불가능한 이론적인 선택 방법(앞으로 누가 가장 사용되지않을지 모르니까)다른 알고리즘과 성능비교를 할 때 참조용으로 쓰임LRU(Least Recently Used, 최근에 가장 사용이 적은 페이지 선택 방법)지역성 이론의 시간의 지역성에 따르면 최근 사용한 데이터가 앞으로도 사용할 확률이 높기 때문에, 최근에 가장 사용을 적게한 페이지가 앞으로도 사용될 확률이 적다는 결론이 나옴실제로도 Optimum 알고리즘에 근접한 성능을 보임하지만 프로그램이 지역성을 띄지 않을 땐 성능이 떨어짐 LRU의 유사 구현 - 클락 알고리즘(Clock Algorithm)접근 비트 하나만 이용함일정 시간 간격마다 모든 페이지의 접근비트를 0으로 초기화함만약 페이지가 참조되었다면 접근비트는 1로 설정 됨일정 시간 간격마다 페이지가 참조되었는지 여부를 확인 할 수 있음향상된 클락 알고리즘(Enhanced Clock Algorithm)이 알고리즘은 접근비트만 이용하는 것이 아니라 변경비트까지 봄스왑영역으로 보내지는 것 중 순위가 높은거슨 접근비트가 0이고, 변경비트도 0인 페이지임그다음으로 접근비트0, 변경비트1 → 접근비트1, 변경비트0 → 접근비트1, 변경비트 1 인페이지 순으로 교체됨LRU만 사용되고 FIFO는 사용되지 않는 것 처럼 보이나, 부득이하게 FIFO를 사용할 때가 있음하드웨어적으로 접근비트를 지원하지 않는 시스템에선 FIFO를 이용함⇒ 어쩔수없이 FIFO의 성능을 높일 수 있는 방법 고안 (2차 기회 페이지 교체 알고리즘)2차 기회 페이지 교체 알고리즘FIFO방식에서 자주 사용하는 페이지에게 또 한번의 기회를 주는 것FIFO방식과 동일하게 동작하지만, 만약 Page Fault 없이 페이지 접근에 성공했다면 해당 페이지를 큐의 맨 뒤로 이동시켜 수명을 연장시켜주는 방식성능 : LRU > 2차 기회 페이지 교체 알고리즘 > FIFO 순 </aside> 스레싱과 워킹셋<aside>CPU 스케쥴링의 목표 : CPU 사용률을 높임방법 : 동시에 실행하는 프로세스의 수 (멀티프로그래밍 정도, Degree of Multiprogramming)를 올림⇒ 어떤 프로세스가 I/O 작업으로 CPU를 사용할 수 없을 때, 다른 프로세스로 컨텍스트 스위칭을 해서 CPU 사용율을 높일 수 있음⇒ CPU 사용율을 높이기 위해 멀티프로그래밍 정도를 늘렸으면, 이 프로세스들이 필요로 하는 공간이 있기 때문에 물리메모리에 프레임을 할당해야함⇒ 하지만, 물리메모리에 할계가 있기때문에 모든 프로세스의 모든 프레임을 물리메모리에 올릴 수 없고, 일부는 스왑영역에 저장됨 스레싱발생 원인 : 근본적인 원인은 물리메모리의 크기가 부족한 것 해결방법 : 프로세스가 실행되면 일정량의 페이지를 할당하고, Page Fault가 발생하면 더 많은 페이지를 할당함  워킹셋현재 메모리에 올라온 페이지는 다시 사용할 확률이 높기 때문에 하나의 세트로 묶어서 메모리에 올림  프로세스가 준비상태에서 실행상태가되는 컨텍스트 스위칭을 할 때 사용됨 회고처음시작할땐 프로그래밍 언어와 SQL정도 공부한 상태라 자료구조, 알고리즘, 운영체제 모두 용어가 겁나고 두려웠었는데 감자님 인강을 통해 그림으로 배우고 많은 예시, 직접 구현등을 해보니까 자신감이 생긴 것 같다.독학하다보니 이렇게 스케쥴을 가지고 공부해본적이 드문데 인강을 뽀개는 법을 배운것 같고, 정처기 실기에서도 LRU 페이지 교체가 나와서 신기했다.. 엮여 있는 것 같아서 앞으로의 내 공부에 많은 영향이 있을 것 같다. 기대된다!

두부

[인프런 워밍업 클럽 2기 - CS] 3주차 미션

운영체제 메모리의 종류는 어떤것들이 있나요? 각 메모리의 특징도 함께 적어주세요.메모리는 레지스터, 캐시, 메인메모리(RAM), 보조저장장치(HDD, SSD)가 있습니다. 레지스터는 CPU의 내부에 존재하는 가장 빠른 메모리로, 휘발성 메모리입니다. CPU가 RAM에서 데이터를 가져왔을 때, 계산하는 역할을 합니다. 캐시는 레지스터와 RAM 사이에 존재하는 휘발성 메모리로, 레지스터와 RAM 사이의 속도 차이를 극복하기 위해서 RAM에서 데이터를 미리 가져와서 저장해두는 역할을 합니다. RAM은 휘발성 메모리로, 운영체제와 실행중인 프로세스들이 올라가는 곳입니다. 보조저장장치는 비휘발성 메모리로, 데이터를 저장하는 역할을 합니다.사용자 프로세스가 메모리의 운영체제 영역에 침범하지 못하도록 만든 레지스터는 어떤 레지스터일까요?경계 레지스터입니다. 경계 레지스터는 CPU 내부에 존재하는 레지스터로, 메모리 관리자가 경계 레지스터 값을 벗어난 사용자 프로세스를 강제 종료시킬 수 있도록 만들어 줍니다.메모리 할당 방식에서 가변 분할 방식과 고정 분할 방식의 장단점은 뭔가요?가변 분할 방식은 메모리를 가변적으로 분할할 수 있어서 코드/힙/스택 등 각 영역을 모듈로 처리할 수 있기 때문에 메모리 접근 보호가 편리하지만, 외부 단편화가 발생할 수 있습니다. 고정 분할 방식은 외부단편화가 발생하지 않으나, 페이지 크기가 고정적이기 때문에 각 영역을 논리적인 영역으로 나눌 수 없으므로 특정 영역만 공유하거나 권한을 부여하는 것이 어렵습니다.CPU 사용률을 올리기 위해 멀티프로그래밍을 올렸지만 스왑이 더 많이 이루어져 CPU 사용률이 0%에 가까워 지는 것을 뭐라고 할까요?스레싱이라고 합니다. 물리 메모리 공간이 한정되어 있기 때문에 일어나는 현상입니다. 하드웨어적인 방법으로는 물리 메모리 크기를 늘려서 해결할 수 있고, 소프트웨어적인 방법으로는 프로세스 실행시간 내에 page fault의 발생빈도에 따라 페이지 크기를 조정하거나 워킹셋을 활용하여 해결할 수 있습니다.HDD나 SSD는 컴퓨터를 실행시키는데 꼭 필요한 걸까요? 이유를 함께 적어주세요.다양한 파일이나 프로그램의 코드들은 비휘발성 메모리에 저장되어야 하므로 컴퓨터를 실행시키는데 꼭 필요한 장치라고 생각합니다.파일을 삭제해도 포렌식으로 파일을 복구할 수 있는 이유가 무엇일까요?파일 시스템은 사용자가 파일 삭제 요청을 했을 때, 파일의 모든 정보를 지우는 것이 아니라 파일 테이블의 헤더를 삭제합니다. 따라서 데이터는 그대로 남아있으므로 포렌식으로 파일을 복구할 수 있습니다.자료구조와 알고리즘지금까지 배운 5개의 정렬 알고리즘의 장단점과 시간 복잡도를 적어주세요.버블/선택/삽입 정렬은 이해와 구현이 쉬우나 시간 복잡도가 O(n²)으로 성능이 좋지 않습니다. 병합/퀵 정렬은 재귀의 개념을 이용하기 때문에 이해와 구현이 비교적 어려우나 시간 복잡도가 O(nlogn)으로 성능이 좋습니다. 다만, 퀵 정렬은 최악의 경우 시간 복잡도가 O(n²)이 될 수 있습니다.메모리가 부족한 시스템에서 어떤 문제를 해결하는데 재귀로 쉽게 구현이 가능할 것 같습니다. 여러분이라면 메모이제이션과 타뷸레이션 중 어떤 걸 이용하실 건가요? 이유를 함께 적어주세요.저는 타뷸레이션을 사용할 것 같습니다. 재귀함수가 더 직관적인 해결법이라면 메모이제이션을 선택하는 게 맞을 수 있겠지만, 메모이제이션은 타뷸레이션에 비해서 메모리 공간을 더 많이 차지하기 때문에 메모리가 부족한 시스템에서는 타뷸레이션이 더 맞는 방법이라고 생각됩니다.

초동

[인프런 워밍업클럽 CS 2기] 3주차 미션

운영체제메모리의 종류는 어떤것들이 있나요? 각 메모리의 특징도 함께 적어주세요.<aside>메모리는 레지스터, 캐시 | 메인메모리(RAM) | 보조저장장치(HDD, SSD)로 나눌 수 있다.레지스터가장 빠른 메모리, CPU내 존재, 휘발성 메모리, bit는 레지스터의 크기임CPU 계산시 레지스터로 가져와서 연산을 하고, 결과는 다시 메인메모리(RAM)에 저장시킴메인메모리에 있는 값을 옮기려면 느리기때문에, 필요한 값은 미리 옮김CPU의 한사이클에 접근할 수 있어서 굉장히 빠름캐시메인메모리에 있는 데이터를 미리 옮긴 곳이 캐시임성능의 이유로 여러개를 둠 (L1, L2, …)CPU의 수~수십 사이클에 접근할 수 있어서 빠름메인메모리실제 운영체제와 다른 프로세스들이 올라가는 공간전원이 꺼지면 데이터가 지워짐 = 휘발성 메모리보조저장장치보다 속도는 빠르지만 가격이 비싸기 때문에 데이터 저장보다는 실행중인 프로그램을 올리는 용도로 사용됨CPU의 수백 사이클에 접근해서 시간이 걸림보조저장장치속도 느림, 용량 큼, 가격 저렴, 비휘발성 메모리CPU 수백만 사이클에 접근해 시간이 많이소요됨 </aside>사용자 프로세스가 메모리의 운영체제 영역에 침범하지 못하도록 만든 레지스터는 어떤 레지스터일까요?<aside>경계 레지스터</aside>메모리 할당 방식에서 가변 분할 방식과 고정 분할 방식의 장단점은 뭔가요?<aside>가변 분할 방식(세그멘테이션)프로세스의 크기에 따라 메모리를 나누는 방식한 프로세스가 메모리의 연속된 공간에 할당되기 때문에 연속 메모리 할당 이라고 함장점 : 메모리가 연속된 공간에 할당되기 때문에 더 크게 할당돼서 낭비되는 공간인 내부 단편화 가 없음단점 : 두개의 빈공간을 합해서 60MB가 있을때, 60MB의 새로운 프로세스를 연속된 공간에 할당하지 못하는 외부 단편화 가 발생함⇒ 조각 모음 : 외부 단편화가 발생한 공간을 합쳐줌조각모음 실행 시, 현재 메모리에서 실행되고 있는 프로세스들의 작업을 일시 중지해야하고, 메모리 공간을 이동시키는 작업을 해야하기 때문에 오버헤드가 발생하게 됨고정 분할 방식(페이징)프로세스의 크기와는 상관없이 정해진 크기로 메모리를 할당하는 방식한 프로세스가 메모리에 분산되어 할당되기 때문에 비연속 메모리 할당 이라고 함장점 : 같은 크기로 나누기 때문에 구현이 간단하고, 오버헤드가 적음단점 : 작은 프로세스도 큰 영역에 할당돼서 공간이 낭비되는 내부 단편화 가 발생함⇒ 해결하는 방법은 없고, 분할되는 크기를 조절해서 내부단편화를 최소화 함</aside>CPU 사용률을 올리기 위해 멀티프로그래밍을 올렸지만 스왑이 더 많이 이루어져 CPU 사용률이 0%에 가까워 지는 것을 뭐라고 할까요?<aside>스레싱⇒ CPU 스케쥴러는 CPU 사용률이 낮아지면 더많은 프로세스를 메모리에 올리게 되고 반복되다보면 어느새 CPU 사용률은 0에 가깝게 떨어지게 되며, 이를 스레싱 이라고 부름</aside>HDD나 SSD는 컴퓨터를 실행시키는데 꼭 필요한 걸까요? 이유를 함께 적어주세요.<aside>HDD는 주변장치로써 버스도 분리되어 있어서 실행에는 필요없다고 느낄 수 있는데 운영체제를 RAM에 올리면 컴퓨터가 끄고 켜질때마다 날아가기때문에 꼭 필요하고, 데이터 스왑시 에서도 필요하다.SSD는 부팅속도나, 프로그램을 실행하고 처리할때 속도면에서 도움을 줘 현대에서는 필수로 자리잡고 있는 것 같다.</aside>파일을 삭제해도 포렌식으로 파일을 복구할 수 있는 이유가 무엇일까요?<aside>파일시스템의 프리블록리스트를 통해 특정 파일을 지워도,파일 테이블의 헤더를 삭제하고 프리블록리스트에 추가하기때문에 사용했던 블록의 데이터는 그대로 남아있어서 복구가 가능하다.</aside>자료구조와 알고리즘지금까지 배운 5개의 정렬 알고리즘의 장단점과 시간 복잡도를 적어주세요.<aside>버블 정렬 : O(n^2)장점 : 구현이 간단하고, 코드가 직관적임단점 : 속도가 느리고, 비효율적임선택 정렬 : O(n^2)장점 : 메모리 사용이 적고, 자료 이동 횟수가 적음단점 : 속도가 느리고, 큰 데이터를 다룰 때 비효율적임삽입 정렬 : O(n^2)장점 : 거의 정렬된 데이터를 처리할 때 효율적임단점 : 데이터가 많을수록 성능이 떨어짐병합정렬 : O(nlogn)장점 : 성능이 지금까지 배운 정렬보다 좋음단점 : 재귀적인 기법을 이용해 이해와 구현이 어려움퀵정렬 : 새타(nlogn), O(n^2)장점 : 성능이 지금까지 배운 정렬보다 좋음단점 : 재귀적인 기법을 이용해 이해와 구현이 어려움 </aside>메모리가 부족한 시스템에서 어떤 문제를 해결하는데 재귀로 쉽게 구현이 가능할 것 같습니다. 여러분이라면 메모이제이션과 타뷸레이션 중 어떤 걸 이용하실 건가요? 이유를 함께 적어주세요.<aside>메모리가 부족한 시스템이라면 결과값을 그때 그때 계산해서 사용하는 메모이제이션을 택할 것 같다. 해시테이블을 이용해 속도도 올리고 계산결과값을 저장하는 장점도 있기 때문이다.</aside>

백엔드

윤승현

[인프런 워밍업 클럽 CS 2기] - CS 3주차 발자국

강의 수강[운영체제]세그멘테이션 : 메모리를 서로 다른 크기의 논리적 단위인 세그먼트로 나누어, 각 세그먼트가 독립적인 주소 공간을 가지도록 관리하는 기법이다.페이징 : 메모리를 할당할 때 정해진 크기의 페이지로 나눈다.페이지드 세그멘테이션 : 세그멘테이션과 페이징을 혼합해 장점을 취한 방식이다. 디맨드 페이징 : 디맨드 페이징은 조만간 필요할 것 같은 데이터를 메모리로 가져오고 쓰이지 않을 것 같은 데이터는 스왑영역으로 이동시키는 정책이다.페이지 교체 정책 : 메모리에 있는 페이지를 스왑영역으로 옮길 때 어떤 페이지를 선택할지 결정하는 정책이다.스레싱 : CPU 사용률을 높이려 했지만 오히려 더 떨어지는 상황을 '스레싱'이라고 한다.워킹셋 : 메모리에 올라온 페이지는 다시 사용할 확률이 높기 때문에 하나의 세트로 묶어서 메모리에 올리는 것을 '워킹셋'이라고 한다. 그리고 프로세스가 준비상태에서 실행상태가 되는 컨텍스트 스위칭을 할 때 사용된다.주변 장치 : 그래픽 카드, 하드디스크, SSD, 키보드, 마우스 등 여러가지가 있다. 그리고 캐릭터 디바이스와 블록 디바이스 두 가지로 나눌 수 있다.마우스/키보드 : 사용자 입력 장치이다.하드디스크 : 기계식으로 저렴하다. 비휘발성 저장 장치이다.Flash Memory(SSD) : 전자식으로 빠르고 고가이다. 비휘발성 저장 장치이다.파일과 파일시스템 : 파일은 데이터를 저장하는 논리적 단위이며, 파일시스템은 이러한 파일들을 효율적으로 저장, 관리, 접근할 수 있도록 조직화하는 구조와 메커니즘입니다.디렉토리 : 파일들을 그룹화하고 계층적으로 조직하여 쉽게 관리하고 접근할 수 있도록 하는 파일 시스템 내의 구조이다.[자료구조와 알고리즘]삽입 정렬장점 : 이해와 구현이 간단하다.단점 : 성능이 O(n²)으로 성능이 좋지 않다.시간 복잡도 : O(n²) 병합 정렬장점 : 성능이 좋다.단점 : 재귀적인 기법으로 이해하기가 조금 어렵다. 그리고 이해와 구현이 어렵다.시간 복잡도 : O(nlogn) 퀵 정렬장점 : 평균적으로 빠른 속도를 내서 성능이 좋다.단점 : 안정적인 정렬을 보장하지 않는다.시간 복잡도 : 평균 시간 복잡도는 O(nlogn), 최악의 경우 시간 복잡도는 O(n²)메모이제이션계산 결과를 캐시에 저장하여 동일한 계산을 반복하지 않고 효율적으로 문제를 해결하는 동적 프로그래밍 기법이다.타뷸레이션문제를 작은 하위 문제로 나누어, 이들을 반복적으로 해결하고 결과를 표 형태로 저장하여 최종 결과를 도출하는 동적 프로그래밍 기법이다.[회고]칭찬하고 싶은 점강의를 들으면서 노션으로 강의 내용을 정리하는 점발자국도 작성하고 미션도 해결한 점모든 강의를 다 들은 점! 아쉬웠던 점역시 시간표대로 학습하지 않은 점.... 일하면서 공부하기 쉽지 않다... 그리고 강의를 들으면 들을 수록 어려워져서 100% 완벽하게 이해하고 넘어가질 못했다. 그래서 이 인프런 워밍업 클럽이 끝나도 강의를 반복해서 들어야 할 것 같다. 마지막 소감3주 동안 강의를 들으면서 공부를 했는데 회사 다니면서 하기 쉽지 않다.... 회사 다니시고 시간표 맞춰서 하시는 분들은 진짜 대단하신 것 같다. 나는 나태해서... 핫핫핫 그래도 시간표대로 강의를 듣지는 않았지만 주차 별로 끊어서 강의를 들으니 강의를 진행함에 있어서 좀 괜찮았다. 미션회고마지막 주차라 그런 건지 몰라도 점점 어려워지는 느낌이라 시간이 쫌 걸렸다. 그래도 끝까지 해결해서 다행이다! ㅎㅎCS 3주차 미션 링크https://www.inflearn.com/blogs/9005

발자국CS발자국인프런워밍업클럽

대협

[인프런 워밍업 클럽 2기 - BE] 3주차 발자국

[인프런 워밍업 클럽 2기 - BE] 3주차 발자국이 블로그는 정보근님의 입문자를 위한 Spring Boot with Kotlin - 나만의 포트폴리오 사이트 만들기 강의 기반으로 코드작성과 코드설명을 적었습니다1. controller test 코드 분석애너테이션 조사@AutoConfigureMockMvcMockMvc를 자동으로 설정해 주는 애너테이션. 이 애너테이션을 통해 HTTP 요청을 수행하고 응답을 확인할 수 있다.MockMvc 란 ?실제로 서버를 띄우지 않고 컨트롤러를 테스트할 수 있는 도구@DisplayName("Test")테스트 클래스를 시작할 때 테스트 클래스의 이름을 지정해서 테스트 리포트에 표시된다.위 코드를 실행시키면 리포트에 TEST 라는 이름으로 테스트 성공유무가 표시됨.@Configuration : Spring에서 Bean을 수동으로 등록하기 위해서 사용메서드 분석 @Test @DisplayName("Introductions 조회") fun testGetIntroductions() { val uri = "/api/v1/introductions" val mvcResult = performGet(uri) val contentAsString = mvcResult.response.getContentAsString(StandardCharsets.UTF_8) val jsonArray = JSONArray(contentAsString) assertThat(jsonArray.length()).isPositive() }api/vi/introduction을 uri 변수에 넣음.HTTP GET 요청을 보낸후, 응답을 문자열로 변환한 후에 JSONArray로 변환JSONArray의 길이가 0보다 큰지 검증, 응답 데이터가 비어 있지 않음을 확인 @Test @DisplayName("Link 조회") fun testGetLinks() { val uri = "/api/v1/links" val mvcResult = performGet(uri) val contentAsString = mvcResult.response.getContentAsString(StandardCharsets.UTF_8) val jsonArray = JSONArray(contentAsString) assertThat(jsonArray.length()).isPositive() } api/vi/links을 uri 변수에 넣음HTTP GET 요청을 보낸후, 응답을 JSONArray로 변환배열의 크기와, 그 데이터가 존재하는지 검증@Test @DisplayName("Resume 조회") fun testGetResume() { val uri = "/api/v1/resume" val mvcResult = performGet(uri) val contentAsString = mvcResult.response.getContentAsString(StandardCharsets.UTF_8) val jsonObject = JSONObject(contentAsString) assertThat(jsonObject.optJSONArray("experiences").length()).isPositive() assertThat(jsonObject.optJSONArray("achievements").length()).isPositive() assertThat(jsonObject.optJSONArray("skills").length()).isPositive() } /api/vi/resume를 uri변수에 넣음GET요청을 보낸후, 응답을 JSONObject로 변환experiences, achievements,skills를 JSONArray로 변환 후 그 값이 양수인지와 데이터가 존재하는지 검증@Test @DisplayName("Projects 조회") fun testProjects() { val uri = "/api/v1/projects" val mvcResult = performGet(uri) val contentAsString = mvcResult.response.getContentAsString(StandardCharsets.UTF_8) val jsonArray = JSONArray(contentAsString) assertThat(jsonArray.length()).isPositive() } /api/vi/projects를 uri 변수에 넣음GET요청을 보낸후 응답 본문을 JSONArray로 변환하고, 배열의 길이가 양수인지와 데이터가 존재하는지 검증private fun performGet(uri: String): MvcResult { return mockMvc .perform(MockMvcRequestBuilders.get(uri)) .andDo(MockMvcResultHandlers.print()) .andReturn() } perform(MockMvcRequestBuilders.get(uri)) : 특정 uri에 GET 요청을 보내는 코드. 서버를 띄우지 않고 API 엔드포인트의 동작을 확인할 수 있음andDo(MockMvcResultHandlers.print()) : 요청과 응답을 콘솔에 출력andReturn() : MvcResult를 반환2. 부분 코드 분석<html *lang*="ko" *xmlns:th*="<http://www.thymeleaf.org>" *th:replace*="~{presentation/layouts/layout-main :: layout(~{::#content})}">Thymeleaf 템플릿 엔진에서 레이아웃을 정의하고 해당 레이아웃을 재사용하는 방식, 템플릿 코드의 중복을 줄이고, HTML 파일 간에 공통 요소를 재사용할 수 있게 하는 것. th:replace="~{presentation/layouts/layout-main :: layout(~{::#content})}"th:replace : 다른 파일을 가져와 현재 위치에 삽입하는 기능 수행~{presentation/layouts/layout-main :: layout(~{::#content})} :~{presentation/layouts/layout-main} : layout-main.html 파일 참조:: layout : layout 이라는 이름의 fragment를 사용하겠다는 의미, 위 코드에서는 layout fragment를 가져오겠다는 뜻(~{::#content}) : id="content" 로 지정된 부분을 layout fragment의 특정 위치에 대체할 것이라는 의미3. interceptor 코드 분석@Component class PresentationInterceptor( private val httpInterfaceRepository: HttpInterfaceRepository ) : HandlerInterceptor { override fun afterCompletion(request: HttpServletRequest, response: HttpServletResponse, handler: Any, ex: Exception?) { val httpInterface = HttpInterface(request) httpInterfaceRepository.save(httpInterface) } }private val httpInterfaceRepository: HttpInterfaceRepository의존성 주입을 통해서 Repository를 사용할 수 있다.override fun afterCompletion(request: HttpServletRequest, response: HttpServletResponse, handler: Any, ex: Exception?) {afterCompletion : HTTP 요청 처리 후에 호출되는 메서드val httpInterface = HttpInterface(request)httpInterfaceRepository.save(httpInterface)request 정보를 담고 있는 httpInterface 객체를 생성 후, httpInterfaceRepository에 저장. @Configuration class PresentationInterceptorConfiguration( private val presentationInterceptor: PresentationInterceptor ) : WebMvcConfigurer { override fun addInterceptors(registry: InterceptorRegistry) { registry.addInterceptor(presentationInterceptor) .addPathPatterns("/**") .excludePathPatterns("/assets/**", "/css/**", "/js/**", "/admin/**", "h2**", "/favicon.ico", "/error") } }addInterceptors인터셉터를 등록하는 메서드registry.addInterceptor(presentationInterceptor)addInterceptor 메서드를 통해 presentationInterceptor를 등록addPathPatterns("/**")모든 요청 경로에 대해 인터셉터 적용excludePathPatterns(...) : 인터셉터가 동작하지 않도록 설정/assets/**: 정적 자원(예: 이미지, 폰트 등)./css/**: CSS 파일./js/**: JavaScript 파일./admin/**: 관리 페이지.h2**: H2 데이터베이스 콘솔./favicon.ico: 사이트 아이콘./error: 오류 처리 경로.[미션4] 조회 REST API 만들기-회고이번 미션을 하면서 @GetMapping 어노테이션에 대해서는 어느정도 이해를 할 수 있었다. 저번 발자국에서 @Id, @GeneratedValue 어노테이션에 대해서 적었지만 아직 부족하다는 걸 알 수 있었고, @ManyToOne 어노테이션에 대해 더 깊이 공부해야겠다는걸 깨달았다. 아직 Spring에 본질적인걸 이해를 못한걸수도 있는거 같다. 코드를 작성하면 할수록 더 깊게 공부를 해야했고, JAVA 문법도 다시 해야겠다는걸 뼈저리게 느끼면서 한것 같다...3주차 회고Spring은 하면 할수록 재밌는건 맞다. Test 코드를 작성할 때도 이래서 이코드가 작동이 되는것도 알 수 있고, 부분적인 걸 따로 모듈화? 해서 만드는것도 재밌다. 이번 워밍업 클럽도 곧 종료가 되는데 java의 중요성도 깨달아서 java공부도 열심히 하고, Spring에 대해서 더 깊게 공부할거다!참고로 중간점검 때 정보근님께서 내가 작성한 질문에 대해 답변을 해주신거 같다. 나의 질문은 이번 워밍업 클럽이 종료가 되면 java의 정석, spring공부를 할건데 추천해줄 강의가 있냐 라는 질문이었다. 답변은 역시 김영한님의 강의였고 다른 강의도 추천해주셨는데 이거는 확인해보고 글을 수정해야겠다...! 무튼, spring을 선택한건 잘한 일 같다...!

백엔드워밍업클럽javakotlinspringTest코드미션4회고록코드설명백엔드

elly

[인프런 워밍업클럽 CS 2기] 3주차 미션

운영체제메모리의 종류는 어떤것들이 있나요? 각 메모리의 특징도 함께 적어주세요.: 레지스터 - 가장 빠른 기억장소로 CPU 내에 존재하고 있고, 휘발성 메모리입니다캐시 - 레지스터는 CPU가 사용하는 메모리로 빠른데, 그에 비해 메인메모리는 너무 느린편이라 메인메모리에 있는 데이터를 레지스터에 옮기려면 한참 걸리기 때문에 필요할 것 같은 데이터를 미리 가져와서 캐시에 저장합니다. 캐시는 휘발성 메모리입니다.메인 메모리 - 실제 운영체제와 다른 프로세스들이 올라가는 공간으로 휘발성 메모리입니다.보조저장장치 - 프로그램 파일들을 저장하고, 비휘발성 메모리입니다.사용자 프로세스가 메모리의 운영체제 영역에 침범하지 못하도록 만든 레지스터는 어떤 레지스터일까요?: 경계 레지스터 입니다.메모리 할당 방식에서 가변 분할 방식과 고정 분할 방식의 장단점은 뭔가요?: 가변 분할 방식 장점 - 메모리에 연속된 공간에 할당되기 때문에 더 크게 할당되서 낭비되는 공간인 ‘내부 단편화’가 없습니다. 단점 - ‘외부 단편화’ 발생합니다.고정 분할 방식 장점 - 구현이 간단하고, 오버헤드가 적습니다. 단점 - 작은 프로세스도 큰 영역에 할당되서 공간이 낭비되는 ‘내부 단편화’가 발생합니다.CPU 사용률을 올리기 위해 멀티프로그래밍을 올렸지만 스왑이 더 많이 이루어져 CPU 사용률이 0%에 가까워 지는 것을 뭐라고 할까요?: 스레싱입니다. 근본적인 원인은 물리메모리의 크기가 부족한 것으로, 하드웨어적으로 해결하려면 메모리 크기를 늘리면 됩니다. 운영체제면으로 해결하게 하려면 프로세스가 실행되는 동안 해당 프로세스에게 맞는 적절한 페이지 수를 결정함으로써 해결합니다.HDD나 SSD는 컴퓨터를 실행시키는데 꼭 필요한 걸까요? 이유를 함께 적어주세요.: 일반적으로 꼭 필요합니다. 왜냐하면 컴퓨터 부팅을 위해 운영체제 실행을 해야하고, 파일 접근이나 프로그램 실행을 위해 필요하기 때문입니다.파일을 삭제해도 포렌식으로 파일을 복구할 수 있는 이유가 무엇일까요?: 파일이 삭제될 때 실제 데이터가 완전히 제거되지 않고, 파일 시스템의 관리 정보만 업데이트되기 때문입니다.만약 특정 파일 삭제 시, 파일시스템은 파일의 모든 정보를 지우는 것이 아니라 파일 테이블의 헤더를 삭제하고 free block list에 추가하는 방법으로 처리하기 때문에 포렌식으로 파일 복구가 가능합니다.  자료구조와 알고리즘지금까지 배운 5개의 정렬 알고리즘의 장단점과 시간 복잡도를 적어주세요.: 버블정렬 장점 - 이해와 구현이 간단함 / 단점 - 성능이 O(n^2)으로 좋지 않음 / 성능 - O(n^2)선택정렬 장점 - 이해와 구현이 간단함 / 단점 - 성능이 O(n^2)으로 좋지 않음 / 성능 - O(n^2)삽입정렬 장점 - 이해와 구현이 간단함 / 단점 - 성능이 O(n^2)으로 좋지 않음 / 성능 - O(n^2)병합정렬 장점 - 성능이 O(nlogn)으로 좋음 / 단점 - 이해와 구현이 어려움 / 성능 - O(nlogn)퀵정렬 장점 - 성능이 O(nlogn)으로 좋음 / 단점 - 이해와 구현이 어려움 / 성능 - O(nlogn) (피벗이 한쪽에 쏠리면 최악의 경우 O(n^2)이긴 함)메모리가 부족한 시스템에서 어떤 문제를 해결하는데 재귀로 쉽게 구현이 가능할 것 같습니다. 여러분이라면 메모이제이션과 타뷸레이션 중 어떤 걸 이용하실 건가요? 이유를 함께 적어주세요.: 메모리가 부족한 시스템에서 문제를 해결할 때는 타뷸레이션을 선택하는 것이 더 좋을 것 같습니다.그 이유는 타뷸레이션은 메모이제이션에 비해 적은 메모리를 사용함에도 불구하고 빠른 시간을 보이기 때문입니다.  회고아직 내용을 완벽하게 이해하지 못하여 이번주 강의를 다시한번 복습할 예정인데, 그래도 미션을 통해 한번 더 살펴보면서 들었던 내용들을 머릿속에 떠올려볼 수 있어서 좋았습니다.또한 메모리 부족 시스템에서의 메모이제이션, 타뷸레이션과 선택과 같이, 현재 가지고 있는 환경에 따라 로직을 어떻게 만들지에 대한 고민이 실제 무엇인가 개발할 때도 중요하다는 생각이 들었습니다.📝⭐️

알고리즘 · 자료구조알고리즘자료구조운영체제

윤승현

[인프런 워밍업 클럽 CS 2기] - CS 3주차 미션

[운영체제] 메모리의 종류는 어떤 것들이 있나요? 각 메모리의 특징도 함께 적어주세요.레지스터 : 가장 빠른 기억장소로 CPU내에 존재하고 있다. 컴퓨터의 전원이 꺼지면 데이터가 사라지기 때문에 휘발성 메모리라고 부른다.캐시 : 레시스터는 CPU가 사용하는 메모리로 굉장히 빠르다. 그에 비해 메인 메모리는 너무 느리다. 메인 메모리에 있는 값을 레지스터로 옮기려면 한참 걸리기 때문에 필요할 것 같은 데이터를 미리 가져오기로 한다. 미리 가져온 데이터를 저장하는 곳이 바로 캐시이다.메인 메모리(RAM) : 메인 메모리는 실제 운영체제와 다른 프로세스들이 올라가는 공간이다. 그리고 전원이 공급되지 않으면 데이터가 지워지기 때문에 휘발성 메모리이다.보조 저장 장치(HDD, SSD) : 가격이 저렴하고 전원이 공급되지 않아도 데이터가 지워지지 않는 비휘발성 메모리이다. 사용자 프로세스가 메모리의 운영체제 영역에 침범하지 못하도록 만든 레지스터는 어떤 레지스터일까요?경계 레지스터 : CPU내에 존재하는 레지스터로 메모리 관리자가 사용자 프로세스가 경계 레지스터의 값을 벗어났는지 검사하고 만약 벗어났다면 그 프로세스를 종료시킨다. 메모리 할당 방식에서 가변 분할 방식과 고정 분할 방식의 장단점은 뭔가요?가변 분할 방식장점은 메모리에 연속된 공간에 할당되기 때문에 더 크게 할당돼서 낭비되는 공간인 “내부 단편화”가 없다.단점은 “외부 단편화”가 발생한다.고정 분할 방식장점은 구현이 간단하고 오버헤드가 적다는 것이다.단점은 작은 프로세스도 큰 영역에 할당돼서 공간이 낭비되는 “내부 단편화”가 발생한다. CPU 사용률을 올리기 위해 멀티프로그래밍을 올렸지만 스왑이 더 많이 이루어져 CPU 사용률이 0%에 가까워 지는 것을 뭐라고 할까요?스레싱이라고 한다. CPU 사용률을 높이려 했지만 오히려 더 떨어지는 상황이 나오는 것이다. HDD나 SSD는 컴퓨터를 실행시키는데 꼭 필요한 걸까요? 이유를 함께 적어주세요.운영체제를 저장하고 실행하기 위해 필수적인 역할을 한다. 그리고 응용 프로그램과 사용자 데이터를 저장하는 장치이기 때문에 필요하다. 파일을 삭제해도 포렌식으로 파일을 복구할 수 있는 이유가 무엇일까요?파일 시스템에서 효율적인 관리를 위해 빈 공간을 모아둔 free block list를 가지고 있다. 만약 특정 파일을 삭제한다면 파일 시스템은 파일의 모든 정보를 지우는 것이 아니라 파일 테이블의 헤더를 삭제하고 free block list에 추가한다. 만약 어떤 파일을 지운다고 가정하면 파일 테이블에서 해당 파일의 헤더를 지워주고 사용했던 블록을 free block list에 넣어준다. 이렇게 처리하면 사용자는 파일이 삭제된 것처럼 느껴지지만 사용했던 블록의 데이터는 그대로 남아있기 때문에 범죄를 저질러서 증거를 인멸하더라도 포렌식을 통해 데이터를 복구할 수 있다.  [자료구조와 알고리즘] 지금까지 배운 5개의 정렬 알고리즘의 장단점과 시간 복잡도를 적어주세요. 버블 정렬장점 : 이해와 구현이 간단하다.단점 : 성능이 O(n²)으로 성능이 좋지 않다.시간 복잡도 : O(n²) 선택 정렬장점 : 이해와 구현이 간단하다.단점 : 성능이 O(n²)으로 성능이 좋지 않다.시간 복잡도 : O(n²) 삽입 정렬장점 : 이해와 구현이 간단하다.단점 : 성능이 O(n²)으로 성능이 좋지 않다.시간 복잡도 : O(n²) 병합 정렬장점 : 성능이 좋다.단점 : 재귀적인 기법으로 이해하기가 조금 어렵다. 그리고 이해와 구현이 어렵다.시간 복잡도 : O(nlogn) 퀵 정렬장점 : 평균적으로 빠른 속도를 내서 성능이 좋다.단점 : 안정적인 정렬을 보장하지 않는다.시간 복잡도 : 평균 시간 복잡도는 O(nlogn), 최악의 경우 시간 복잡도는 O(n²) 메모리가 부족한 시스템에서 어떤 문제를 해결하는데 재귀로 쉽게 구현이 가능할 것 같습니다. 여러분이라면 메모이제이션과 타뷸레이션 중 어떤 걸 이용하실 건가요? 이유를 함께 적어주세요.메모리가 부족한 시스템에서는 타뷸레이션이 더 적합하다고 생각합니다.그 이유는 재귀 호출로 인한 스택 오버플로우 위험도 없고 메모리도 절약하고 속도도 빠르게 해결할 수 있기 때문입니다.  

인프런워밍업클럽CS미션

helloyl

인프런 워밍업 클럽 스터디 2기 - CS 3주차 미션

운영체제메모리의 종류는 어떤 것들이 있나요? 각 메모리의 특징도 함께 적어주세요.레지스터가장 빠른 저장 장소, 휘발성 메모리캐시메인 메모리에서 미리 가져온 데이터를 저장메인 메모리휘발성 메모리, 실행 중 프로그램을 올림보조저장장치비휘발성 메모리사용자 프로세스가 메모리의 운영체제 영역에 침범하지 못하도록 만든 레지스터는 어떤 레지스터일까요?경계 레지스터메모리 할당 방식에서 가변 분할 방식과 고정 분할 방식의 장단점은 뭔가요?가변 분할 방식장점 : 내부 단편화 없음단점 : 외부 단편화 발생고정 분할 방식장점 : 구현이 간단함, 오버헤드가 적음단점 : 내부 단편화 발생CPU 사용률을 올리기 위해 멀티프로그래밍을 올렸지만 스왑이 더 많이 이루어져 CPU 사용률이 0%에 가까워 지는 것을 뭐라고 할까요?스레싱HDD나 SSD는 컴퓨터를 실행시키는데 꼭 필요한 걸까요? 이유를 함께 적어주세요.필요함, 컴퓨터를 실행시킬 때 필요한 파일들이 저장되어있음파일을 삭제해도 포렌식으로 파일을 복구할 수 있는 이유가 무엇일까요?파일 시스템이 파일의 모든 정보가 아닌 파일 테이블의 헤더를 삭제하고 Free Block List에 추가함사용했던 블록의 데이터는 그대로 남아있음자료구조와 알고리즘지금까지 배운 5개의 정렬 알고리즘의 장단점과 시간 복잡도를 적어주세요.버블 정렬장점 : 이해와 구현이 간단단점 : 성능 좋지 않음시간 복잡도 : O(n^2)선택 정렬장점 : 이해와 구현이 간단단점 : 성능 좋지 않음시간 복잡도 : O(n^2)삽입 정렬장점 : 이해와 구현이 간단단점 : 성능 좋지 않음시간 복잡도 : O(n^2)병합 정렬장점 : 성능 좋음단점 : 이해와 구현이 어려움시간 복잡도 : O(nlogn)퀵 정렬장점 : 성능 좋음단점 : 이해와 구현이 어려움시간 복잡도 : Θ(nlogn) ~ O(n^2)메모리가 부족한 시스템에서 어떤 문제를 해결하는데 재귀로 쉽게 구현이 가능할 것 같습니다. 여러분이라면 메모이제이션과 타뷸레이션 중 어떤 걸 이용하실 건가요? 이유를 함께 적어주세요.타뷸레이션적은 메모리 사용임에도 성능이 좋음

알고리즘 · 자료구조

또니

[인프런 워밍업 클럽 2기 CS] 3주차 미션

[운영체제]메모리의 종류는 어떤것들이 있나요? 각 메모리의 특징도 함께 적어주세요. => CPU에 존재하고 휘발성 메모리인 레지스터, 메인 메모리에 있는 값을 레지스터로 옮기는 시간을 줄이기 위해 데이터를 가져와 저장하는 캐시, 실제 운영체제와 프로세스가 올라가는 휘발성 메모리인 메모리, 비휘발성이며 작업된 데이터를 저장하는 보조 저장장치가 있습니다.사용자 프로세스가 메모리의 운영체제 영역에 침범하지 못하도록 만든 레지스터는 어떤 레지스터일까요?=> 경계 레지스터 메모리 할당 방식에서 가변 분할 방식과 고정 분할 방식의 장단점은 뭔가요?=> 가변분할 방식은 프로세스 크기에 따라 메모리를 할당하기 때문에 내부 단편화가 일어나지 않지만 외부 단편화가 발생합니다. 고정분할 방식은 외부 단편화를 해결하고, 메모리 관리를 효율적으로 하지만 내부 단편화가 일어나는 단점이 있습니다.CPU 사용률을 올리기 위해 멀티프로그래밍을 올렸지만 스왑이 더 많이 이루어져 CPU 사용률이 0%에 가까워 지는 것을 뭐라고 할까요?=> 스레싱 HDD나 SSD는 컴퓨터를 실행시키는데 꼭 필요한 걸까요? 이유를 함께 적어주세요.=> 컴퓨터를 활성화 시키기 위해선 CPU를 동작시켜야하는데 이때 운영체제가 필요하다. 이때 운영체제가 저장되어야하는데, RAM과 같은 메모리는 휘발성이므로 저장을 할 수 없지만 HDD나 SSD는 비휘발성으로 운영체제를 저장하여 사용하기 때문에 필요하다.파일을 삭제해도 포렌식으로 파일을 복구할 수 있는 이유가 무엇일까요?=> 파일을 삭제하면 모든 정보를 지우는 것 보다 헤더를 삭제하고 free block list에 추가한다. 이때 사용했던 데이터 블록이 그대로 저장되어 있어 복구할 수 있다.[자료구조와 알고리즘]1. 지금까지 배운 5개의 정렬 알고리즘의 장단점과 시간 복잡도를 적어주세요.버블 정렬장점: 가장 단순하고 이해가 쉽다.단점: 성능이 좋지 않다.시간 복잡도: O(n^2)선택 정렬장점: 이해와 구현이 간단하다.단점: 성능이 좋지 않다.시간 복잡도: O(n^2)삽입 정렬장점: 이해와 구현이 간단하다.단점: 성능이 좋지 않다.시간 복잡도: O(n^2)병합 정렬장점: 버블, 선택, 삽입 정렬보다 성능이 좋다.단점: 이해하기 어렵고, 구현하기 어렵다.시간 복잡도: O(n log n)퀵 정렬장점: 적은 메모리 공간을 사용해 성능이 좋다.단점: 이해하기 어렵고, 구현하기 어렵다. 시간복잡도: O(n log n)메모리가 부족한 시스템에서 어떤 문제를 해결하는데 재귀로 쉽게 구현이 가능할 것 같습니다. 여러분이라면 메모이제이션과 타뷸레이션 중 어떤 걸 이용하실 건가요? 이유를 함께 적어주세요.=> 메모이제이션은 재귀를 사용기 때문에 메모리 비용이 크지만, 타뷸레이션은 반복문을 사용하기 때문에 메모리의 크기를 예측 할 수 있습니다. 때문에 타뷸레이션을 사용할 것 같습니다.알고리즘 강의 링크 👉그림으로 쉽게 배우는 자료구조와 알고리즘 (기본편)운영체제 강의 링크 👉그림으로 쉽게 배우는 운영체제

알고리즘 · 자료구조CS지식인프런워밍업클럽2기

tenenger

인프런 워밍업 클럽 CS 2기 - 3주차 발자국

자료 구조 및 알고리즘 삽입 정렬배열을 정렬된 부분, 정렬되지 않은 부분 총 두 영역으로 나누어, 정렬되지 않은 부분에서 데이터를 하나씩 꺼내어 정렬된 부분에 삽입하는 정렬 알고리즘이다.시간 복잡도는 O(n²)이다.function insertionSort (arr) { for (let i=1; i<arr.length; i++) { const memoried = arr[i]; let j; for (j=i-1; j>=0; j--) { if (arr[j] > memoried) arr[j+1] = arr[j]; else break; } arr[j+1] = memoried; } return arr; } console.log(insertionSort([4,1,3,5])) // [1,3,4,5] 병합 정렬병합 정렬은 분할 정복을 이용하여 재귀적으로 정렬하는 알고리즘이며, 배열을 반으로 분할하고 다시 병합한다.분할은 log n, 병합할 때 비교는 n이 걸리므로, 시간 복잡도는 O(n log n)이다.function mergeSort(arr) { if (arr.length <= 1) return arr; const mid = Math.floor(arr.length / 2); const leftArr = mergeSort(arr.slice(0, mid)); const rightArr = mergeSort(arr.slice(mid)); const sorted = []; let left = 0; let right = 0; while (left < leftArr.length && right < rightArr.length) { if (leftArr[left] < rightArr[right]) { sorted.push(leftArr[left]); left++; } else { sorted.push(rightArr[right]); right++; } } while (left < leftArr.length) { sorted.push(leftArr[left]); left++; } while (right < rightArr.length) { sorted.push(rightArr[right]); right++; } return sorted; } console.log(mergeSort([3,5,2,4,1,7,8,6])) 퀵 정렬병합 정렬은 분할 정복을 이용하여 재귀적으로 정렬하는 알고리즘이며, 배열에서 하나의 숫자를 '피벗'으로 선택한 뒤 작은 값은 왼쪽, 큰 값은 오른쪽으로 분할 다시 병합한다.시간복잡도의 평균은 O(n log n)이지만, 피벗에 따라 O(n²) 일 수도 있다.퀵 정렬은 병합 정렬보다 더 적은 메모리와 비교하는 횟수가 더 적어서 효율적인 경우가 있다.function quickSort (arr, left = 0, right = arr.length - 1) { if (left < right) { const pivotIndex = partition(arr, left, right); quickSort(arr, left, pivotIndex - 1); quickSort(arr, pivotIndex + 1, right); } return arr; } function partition (arr, left, right) { const pivot = arr[left]; let low = left + 1; let high = right; while (low <= high) { while (low <= high && arr[low] < pivot) { low++ } while (low <= high && pivot < arr[high]) { high--; } if (low < high) { [arr[low], arr[high]] = [arr[high], arr[low]]; } } [arr[left], arr[high]] = [arr[high], arr[left]]; return high; } console.log(quickSort([3,5,2,4,1,7,8,6])) // [ 1, 2, 3, 4, 5, 6, 7, 8 ] 동적 프로그래밍 - 메모이제이션재귀 함수는 중복된 계산을 여러 번 수행하여 성능이 좋지 않다.메모이제이션은 계산된 값을 저장하고 이를 다시 사용하여 성능을 높일 수 있다.function fibonacci(n ,memo = {}) { if (n <= 1) return n; if (!memo[n]) { memo[n] = fibonacci(n - 2, memo) + fibonacci(n - 1, memo) } return memo[n] } console.log(fibonacci(5)) 동적 프로그래밍 - 타뷸레이션타뷸레이션은 상향식 접근 방식으로, 필요하지 않는 결과값도 계산하여 재귀를 사용하지 않기 때문에 메모제이션보다 더 빠를 수 있다.특히 재귀적이지 않기 때문에 메모리를 절약할 수 있다.function fibonacciTabulation(n) { const table = [0, 1] for (let i=2; i<=n; i++) { table[n] = fibonacciTabulation(n - 2) + fibonacciTabulation(n - 1) } return table[n] } console.log(fibonacciTabulation(5)) 미션1지금까지 배운 5개의 정렬 알고리즘의 장단점과 시간 복잡도를 적어주세요.버블 정렬장점: 구현이 간단하고, 이미 정렬된 경우 시간 복잡도가 O(n)이다.단점: 평균 및 최악의 경우 시간 복잡도가 O(n²)이다.시간 복잡도:최선: O(n)평균: O(n²)최악: O(n²)선택 정렬장점: 구현이 간단하다.단점: 항상 시간 복잡도가 O(n²)이다.시간 복잡도:최선: O(n²)평균: O(n²)최악: O(n²)삽입 정렬장점: 작은 데이터 집합에 대해 빠르게 동작하며, 안정적인 정렬 알고리즘이다.단점: 평균 및 최악의 경우 시간 복잡도가 O(n²)이다.시간 복잡도:최선: O(n)평균: O(n²)최악: O(n²)병합 정렬장점: 분할 병합 방식으로 시간 복잡도가 O(n log n)이다.단점: 추가적인 메모리 공간이 필요하여, 공간 복잡도가 O(n)이다.시간 복잡도:최선: O(n log n)평균: O(n log n)최악: O(n log n)퀵 정렬장점: 분할 병합 방식으로 O(n log n)의 시간 복잡도를 가지고, 메모리 사용이 효율적이다.단점: 최악의 경우 O(n²)이다.시간 복잡도:최선: O(n log n)평균: O(n log n)최악: O(n²)메모리가 부족한 시스템에서 어떤 문제를 해결하는데 재귀로 쉽게 구현이 가능할 것 같습니다. 여러분이라면 메모이제이션과 타뷸레이션 중 어떤 걸 이용하실 건가요? 이유를 함께 적어주세요.타뷸레이션을 선택할거 같습니다.메모이제이션의 경우 재귀적으로 함수를 호출하기 때문에 함수를 생성하면 메모리를 차지하고, 함수가 종료되기 전까지 점유합니다. 반면에 타뷸레이션의 경우 재귀적으로 함수를 호출하지 않기 때문에 하나의 함수에 해당되는 메모리만 차지하기 때문에 메모리가 부족한 시스템에 더 적합합니다. 운영체제 및 CS 가상메모리물리메모리의 크기보다 프로세스가 요구하는 메모리 크기가 클 경우에 보조저장장치의 스왑 영역을 활용하여 메모리의 크기를 늘리는데, 물리메모리 + 스왑영역을 합쳐서 가상메모리라고 부른다.만약 CPU의 비트가 32bit인 경우, 가상메모리의 크기는 4GB까지 가능하다. 메모리 관리자는 프로세스가 메모리의 논리주소를 요구할 경우 물리 메모리의 물리주소를 전달해주는데, 이를 동적 주소 변환이라고 한다.메모리 관리자가 매핑 테이블을 이용하여 논리주소를 물리주소로 변환할 수 있다. 세그먼테이션(배치 정책)프로세스에 메모리를 할당해주는 배치 정책 중 가변적으로 메모리를 할당해준다고 해서 세그먼테이션이라고 한다. 메모리 관리자는 논리주소를 세그먼테이션 테이블에서 물리주소로 변환할 수 있는 정보를 가지고 물리주소로 변환한다.세그먼테이션 테이블에는 세그먼트 번호, Base Address, Bound Address 가 있다. 논리주소를 물리주소로 변환하는 과정프로세스가 논리주소를 요청할 때, 메모리관리자는 세그먼트 번호를 찾아낸다.메모리 관리자는 Segment Table Base Register를 이용해 물리메모리에 있는 세그먼테이션 테이블을 찾는다.세그먼테이션 테이블에서 세그먼테이션 번호와 일치되는 행의 정보를 얻는다.Bound Address보다 논리주소가 클 경우 메모리 침범 인터럽트를 발생시켜 프로그램을 종료시키고, 크지 않을 경우 Base Address + 논리 주소를 합쳐 물리주소를 변환하여 프로세스에게 전달한다. 세그멘테이션은 메모리를 가변적으로 분할 할 수 있고, 코드영역, 힙영역, 데이터영역, 스택 영역 등을 모듈로 관리할 수 있어 메모리 접근 보호가 편리한 장점이 있다.반면, 외부 단편화가 발생하기 때문에 분할되어 있는 메모리의 공간보다 큰 메모리를 요구하는 프로세스가 있는 경우, 메모리 공간을 합쳐여하는 오버헤드가 발생하는 단점이 있다. 페이징(배치 정책)프로세스에 메모리를 할당해주는 배치 정책 중 고정적으로 메모리를 할당해준다고 해서 페이징이라고 한다. 논리 주소 공간에서 페이징은 페이지라고 불리고, 물리 주소 공간에서 페이징은 프레임이라고 불린다. 메모리 관리자는 논리주소를 페이지 테이블에서 물리주소로 변환할 수 있는 정보를 가지고 물리주소로 변환한다.페이지 테이블에는 인덱스, 프레임이 있다. 논리주소를 물리주소로 변환하는 과정프로세스가 논리주소를 요청할 때, 메모리관리자는 인덱스와 오프셋을 구한다.인덱스는 (논리주소 / 페이지 크기)의 몫오프셋은 (논리주소 / 페이지 크기)의 나머지메모리 관리자는 Page Table Base Register를 이용해 물리메모리에 있는 페이지 테이블을 찾는다.세그먼테이션 테이블에서 세그먼테이션 번호와 일치되는 행의 정보를 얻어 프레임을 얻는다.프레임의 물리주소과 오프셋을 합산하여 실제 물리주소를 계산하여 프로세스에게 물리주소를 전달한다. 페이징은 메모리를 세그먼테이션보다 쉽게 구현할 수 있는 장점이 있다.반면, 내부단편화가 발생하기 때문에 낭비되는 메모리 공간이 발생하고, 코드영역, 힙영역, 데이터영역, 스택 영역 등을 메모리에 할당해야하기 때문에 논리적으로 분할 할 수 없고, 메모리 접근 보호가 어려우며, 프로세스가 많아지면 페이지 테이블이 많아지고 메모리 공간을 차지 하기 때문에 사용자 메모리 공간이 줄어드는 단점이 있다. 페이지드 세그멘테이션(배치 정책)세그멘테이션과 페이지의 혼합한 배치정책이다. 메모리 관리자는 논리주소를 페이지드 세그멘테이션 테이블에서 물리주소로 변환할 수 있는 정보를 가지고 물리주소로 변환한다.페이지드 세그멘테이션은 2개의 테이블을 가지는데, 세그멘테이션 테이블과 페이지 테이블이다.세그멘테이션 테이블은 세그먼트번호, 권한비트, 페이지넘버, Bound Address를 가진다.페이지 테이블은 인덱스, 프레임을 가진다. 메모리 접근권한은 읽기, 쓰기, 실행 권한이 있다.프로세스의 영역별 권한은 아래와 같다.코드 영역: 읽기와 실행 가능, 수정 불가데이터 영역: 읽기와 쓰기 가능, 실행 불가능스택 & 힙 영역: 읽기와 쓰기 가능, 실행 불가능 페이지드 세그멘테이션에서 논리주소를 물리주소로 변환할 때 권한도 확인한다. 논리주소를 물리주소로 변환하는 과정프로세스가 논리주소를 요청할 때, 메모리관리자는 세그멘테이션 번호를 찾아낸다.세그먼테이션 테이블에서 세그먼테이션 번호와 일치되는 행의 정보를 얻어 권한이 위반하면 인터럽트를 발생시켜 프로그램을 종료시키고, 위반하지 않으면 페이지넘버와 페이지 개수를 얻는다.페이지 테이블에서 접근한 페이지 넘버와 일치되는 행의 프레임을 얻는다.프레임과 페이지 개수를 합산한 물리 주소를 프로세스에 전달한다. 테이블을 확인하기 위해 메모리에 2번 접근해야하는 단점이 있어 현대에서는 페이징과 페이지드 세그멘테이션을 적절하게 사용하고 있다. 디멘드 페이징(가져오기 정책)메모리에 사용할것 같은 프로세스를 메모리에 올리고, 그렇지 않은 프로세스는 스왑영역에 위치시켜 메모리를 효율적으로 사용하는 정책이다. 지역성 이론시간적 지역성: 최근에 접근한 데이터는 다시 접근할 가능성이 높다.공간적 지역성: 현재 접근한 데이터와 가까운 위치에 있는 데이터가 곧 접근될 가능성이 높다. 스왑영역에서 메모리로 가져오는 것을 스왑인, 반대로 메모리에서 스왑영역으로 내보내는 것을 스왑아웃이라고 한다. 페이지 테이블의 한 행을 페이지 엔트리(PTE)라고 불리고, 여러 비트를 통해 물리메모리의 프레임 또는 스왑영역의 위치를 알 수 있다.접근 비트: 페이지가 메모리에 올라온 후 접근 유무변경 비트: 페이지 데이터의 변경 유무유효 비트: 페이지가 물리 메모리에 있는지 스왑 영역에 있는지 유무(1은 스왑영역에 있다는 뜻)읽기/쓰기/실행 비트: 페이지에 대한 접근 권한 Page Fault프로세스가 가상주소를 요청하고 메모리 관리자가 페이지 테이블을 통해 프레임이 물리 메모리에 없으면 Page Fault 인터럽트가 발생한다.그리고 프로세스는 대기 상태에 들어가고, 메모리 관리자는 스왑인을 통해 물리 메모리에 프레임을 옮기고 다시 재시작된다. 페이지 교체 정책메모리 공간이 부족할 때 어떤 페이지를 스왑 영역으로 보낼지 결정하는 중요한 알고리즘이다. 주요 페이지 교체 정책1. Random- 페이지를 랜덤으로 교체한다.- 지역성 이론을 고려하지 않고 자주 사용되는 페이지도 보낼 수 있기 때문에 거의 사용되지 않는다.2. FIFO(First In First Out)- 가장 먼저 메모리에 들어온 페이지 교체한다.- 구현이 간단하지만 자주 사용되는 페이지도 교체될 수 있다.3. Optimum- 앞으로 오랫동안 사용되지 않을 페이지 교체한다.- 이상적인 알고리즘이나 구현하기 어렵다.4. LRU(Least Recently Used)- 가장 최근에 사용되지 않은 페이지 교체한다.- 최근 사용된 페이지가 다시 사용될 확률이 높다는 가정에 따라 동작한다.LRU를 유사하게 구현하기 위한 알고리즘1. Clock Algorithm페이지 테이블의 접근 비트를 사용하여, 일정 시간 동안 참조된 페이지인지 아닌지 확인한다.클락 핸드가 시계 방향으로 움직이며, 접근 비트가 0인 페이지를 교체한다.Enhanced Clock Algorithm은 변경 비트까지 고려한다.2. Second Chance AlgorithmFIFO 방식의 문제점을 보완하여 맨 처음 페이지가 최근에 사용된 경우 큐의 맨 뒤로 이동시켜 수명 연장한다.스레싱과 워킹셋스레싱은 CPU 사용률이 떨어지는 현상이다.Page Falut가 발생하면 CPU 사용하는 것보다 스왑인, 스왑아웃 동작하는데 자원을 소모하여 CPU 사용률이 떨어지고, 그렇다고 메모리에 페이지를 많이 올리게 되면 프로세스가 사용해야할 페이지가 줄어들어 CPU 사용률이 떨어진다. 워킹셋(Working Set)현재 메모리에 올라와 있는 페이지는 자주 사용할 확률이 높기 때문에 하나의 세트로 묶는데 이를 워킹셋이라고 한다.프로세스가 준비상태에서 컨텍스트 스위칭을 통해 실행상태로 변경할 때 사용한다.주변장치(I/O, 디바이스, 저장장치)그래픽카드, 마우스, 키보드, 하드디스크 등을 주변장치라고 한다. 주변장치는 메인보드의 버스를 통해 연결되고, Address 버스, data 버스, control 버스가 있다.주변장치의 레지스터는 입출력 데이터를 저장하는 역할을 한다. 주변장치는 캐릭터 디바이스, 블록 디바이스로 나뉜다.캐릭터 디바이스는 적은 양의 데이터(문자)를 전송하는 장치로, 마우스나 키보드가 있다.블록 디바이스는 많은 양의 데이터를 전송하는 장치로, 하드디스크가 있다.초기에는 CPU가 I/O 요청을 대기해야해서 CPU 사용률이 떨어졌고, 이를 해결하기 위해 입출력 제어기가 도입되어 I/O 작업을 CPU 대신 관리한다.입출력 제어기는 CPU와 메모리를 연결하는 시스템 버스, 주변장치를 연결하는 입출력 버스로 구성되어 있다.그래픽카드는 빠른 속도를 위해 시스템 버스에 연결한다.입출력 버스는 고속과 저속으로 나뉘는데, 고속은 하드디스크과 연결하고 저속은 마우스, 키보드와 연결한다.입출력 데이터를 저장하기 위해서 CPU 도움이 필요한데, DMA 를 통해 CPU 도움없이 주변장치가 메모리에 접근가능하다.CPU로 접근하는 메모리와 DMA로 접근하는 메모리는 다른데, DMA로 접근하는 메모리는 Memory Mapped I/O 라고 한다.마우스, 키보드볼 마우스는 잔 고장이 많았다.광학 마우스는 마우스 아래에 달린 카메라를 통해 1500회 이상을 사진으로 촬영해 마우스 좌표값을 얻는다.마우스 이벤트 전달마우스의 디바이스 컨트롤러의 DSP를 통해 좌표값을 얻는다.마우스 드라이버가 DSP에서 좌표값을 가져간다.마우스 드라이버가 CPU에 인터럽트를 보내고, 좌표 데이터 또는 클릭 이벤트를 전달해준다.운영체제가 Foreground로 프로세스에게 이벤트를 전달해준다.키보드도 마우스와 유사하게 사용자가 입력한 키를 디바이스 컨트롤러가 감지해 CPU로 인터럽트를 보내고, 운영체제가 Foreground로 프로세스에게 이벤트를 전달해준다. 하드디스크하드디스크는 Spindle이 있고, 여러개의 Platter가 있다.Platter는 disk arm에 달린 read/write head를 통해 읽고 쓰며, 자성을 띄기 때문에 N극은 0 S극은 1이다.여러개의 Platter에 track이 같은 위치에 있는 것을 Cylinder라고 한다.Sector는 하드디스크의 가장 작은 단위이다.하드디스크는 헤드를 통해 읽고, 데이터를 읽는 시간을 Seek Time이라고 한다.헤드를 통해 데이터를 찾기 때문에 찾는 시간이 오래걸린다. SSD는 HDD와 달리 물리적으로 데이터를 읽는 것이 아니라 전기적으로 읽고 쓰기 때문에 빠르고, 조용하다. 파일과 파일시스템파일은 사용자가 운영체제에 관리를 요청하면, 운영체제는 파일시스템을 통해 파일을 관리한다. 파일 시스템은 아래의 기능을 제공한다.파일 및 디렉토리 생성,수정, 삭제파일 접근 권한 관리데이터 무결성 보장백업 및 복구암호화파일은 블록 디바이스인데, 사용자가 바이트 단위로 읽으려면 파일 시스템을 통해 읽을 수 있다.파일의 정보는 FCB가 있는데 FCB를 통해 사용자는 시스템 콜인 open(), close() 함수를 통해 파일을 열고 닫을 수 있다. 순차 파일 구조는 카세트 테이프처럼 데이터가 연속적으로 저장되는 구조이며 구조가 단순하여 공간 낭비가 적다. 만약 특정 위치로 이동하려면 lseek() 시스템 콜 함수를 통해 접근할 수 있고, 이는 단점으로 데이터 수정 및 삭제하는데 시간이 오래걸린다.직접 파일 구조는 해시 함수를 이용해 데이터를 저장하는 방식으로, 해시 함수에 따라 성능에 영향을 준다.인덱스 파일 구조: 순차 접근과 직접 접근의 장점을 결합한 방식으로, 인덱스 테이블을 이용해 빠른 접근이 가능하다. 디렉토리파일은 데이터를 갖고 있고, 디렉토리는 파일 정보를 갖고 있는 파일이다. 파일과 디스크파일이 저장될 때, 디스크는 일정 크기로 나뉜 블록으로 데이터를 저장한다.데이터 저장방식은 연속할당, 불연속할당이 있다.연속 할당은 연속적으로 데이터를 저장하며 외부 단편화가 발생한다.불연속 할당은 분산하여 데이터를 저장하며 내부 단편화가 발생한다.연결 할당은 연결 리스트 자료구조로 데이터를 연결하여 접근한다.인덱스 할당은 별도의 인덱스 블록을 통해 데이터에 접근한다. 파일시스템은 비어있는 블록을 별도로 관리하는데, 이를 free block list라고 한다.파일을 삭제할 때 실제 파일이 삭제되는 것이 아니라, 파일의 헤더만 삭제하고 사용했던 블록을 free block list에 추가한다.그래서 포렌식으로 데이터를 복구할 때 실제 데이터는 존재하기 때문에 복구가 가능하다. 미션2메모리의 종류는 어떤것들이 있나요? 각 메모리의 특징도 함께 적어주세요.레지스터CPU가 처리하기 위해 메인메모리에 있는 값을 레지스터로 가져와 계산을 하고, 결과값을 메인메모리에 저장한다. 레지스터는 CPU에 존재한다.전력이 끊기면 데이터가 사라지는 휘발성 메모리이다.캐시메인메모리의 있는 값을 레지스터로 가지고 올 때, 성능을 위해 미리 값을 가져온다.캐시는 CPU에 L1, L2, L3... 등으로 존재한다.전력이 끊기면 데이터가 사라지는 휘발성 메모리이다.메인메모리(RAM)운영체제나 프로세스가 올라가는 공간이다.전력이 끊기면 데이터가 사라지는 휘발성 메모리이다.보조저장장치(HDD, SDD)전력이 끊겨도 데이터가 유지되는 비휘발성 메모리이다.파일, 데이터를 저장하는 공간이다. 가격 : 레지스터 > 캐시 > 메인메모리 > 보조저장장치용량 : 레지스터 < 캐시 < 메인메모리 < 보조저장장치속도 : 레지스터 > 캐시 > 메인메모리 > 보조저장장치사용자 프로세스가 메모리의 운영체제 영역에 침범하지 못하도록 만든 레지스터는 어떤 레지스터일까요?경계 레지스터메모리 할당 방식에서 가변 분할 방식과 고정 분할 방식의 장단점은 뭔가요?  가변 분할 방식 장점은 낭비되는 메모리 공간이 없다.(내부 단편화 없음)단점은 메모리 할당된 2개의 프로세스가 종료되고 2개의 프로세스의 요구하는 만큼 메모리 공간을 요구하는 프로세스가 발생할 경우, 실행중인 프로세스를 종료하고 메모리를 합쳐야하는 오버헤드가 발생한다.(외부 단편화)고정 분할 방식장점은 구현이 단순하고 오버헤드가 적다단점은 낭비되는 메모리 공간이 있다.(내부 단편화)CPU 사용률을 올리기 위해 멀티프로그래밍을 올렸지만 스왑이 더 많이 이루어져 CPU 사용률이 0%에 가까워 지는 것을 뭐라고 할까요?스레싱5. HDD나 SSD는 컴퓨터를 실행시키는데 꼭 필요한 걸까요? 이유를 함께 적어주세요.초기의 컴퓨터는 필수적인 장치가 아니었습니다. 그러나 컴퓨터가 발전하면서 운영체제를 통해 컴퓨터를 효율적으로 관리하고, 개인 데이터를 저장하기 위해서 오늘날에는 거의 필수로 필요한 저장장치가 되었습니다.파일을 삭제해도 포렌식으로 파일을 복구할 수 있는 이유가 무엇일까요?파일 삭제시 파일의 헤더만 삭제하고 실제 데이터는 존재하기 때문에, 포렌식으로 파일을 복구할 수 있습니다.

알고리즘 · 자료구조인프런워밍업클럽CS2기

elly

[인프런 워밍업클럽 CS 2기] 3주차 발자국

3주차 학습 내용 '그림으로 쉽게 배우는 자료구조와 알고리즘 (기본편)' Section 3(Unit 6~10)'그림으로 쉽게 배우는 운영체제' Section 8, 9, 10 '그림으로 쉽게 배우는 자료구조와 알고리즘 (기본편)' Section 3(Unit 6~10) Section 3. 알고리즘정렬 - 병합정렬(Merge Sort)divide and conquer - 분할 정복해결하기 힘든 문제가 발생한다면 이걸 한 번에 해결하려고 하지 말고, 해결하기 쉬울 정도로 문제를 쪼갠 다음 하나씩 해결하라원소를 하나일 때까지 쪼개고, 역순으로 순서에 맞게 하나의 배열로 병합해줌 (재귀함수를 호출한 모양과 비슷함)코드 구현function MergeSort(arr, leftIndex, rightIndex) { if(leftIndex < rightIndex) { let midIndex = parseInt((leftIndex + rightIndex) / 2); MergeSort(arr, leftIndex, midIndex); MergeSort(arr, midIndex + 1, rightIndex); Merge(arr, leftIndex, midIndex, rightIndex); } } function Merge(arr, leftIndex, midIndex, rightIndex) { let leftAreaIndex = leftIndex; let rightAreaIndex = midIndex + 1; let tempArr = []; tempArr.length = rightIndex + 1; tempArr.fill(0, 0, rightIndex + 1); let tempArrIndex = leftIndex; while(leftAreaIndex <= midIndex && rightAreaIndex <= rightIndex) { if(arr[leftAreaIndex] <= arr[rightAreaIndex]) { tempArr[tempArrIndex] = arr[leftAreaIndex++]; } else { tempArr[tempArrIndex] = arr[rightAreaIndex++]; } tempArrIndex++; } if(leftAreaIndex > idIndex) { for(let i = rightAreaIndex; i <= rightIndex; i++) { tempArr[tempArrIndex++] = arr[i]; } } else { for(let i = leftAreaIndex; i <= midIndex; i++) { tempArr[tempArrIndex++] = arr[i]; } } } 병합정렬 성능성능측정 부분은 Merge() 함수 내 흩어진 배열을 합치는 부분하나의 데이터와 하나의 데이터가 두 개로 합쳐질 때 비교 연산을 두 번 함두 개의 데이터와 두 개의 데이터가 네개로 합쳐질 때 비교가 네 번 이뤄짐각 단계를 거칠 때마다 영역의 수가 반으로 줄어 logn이 됨분할된 배열을 병합할 때는 n개의 데이터를 n번 비교하므로 O(nlogn) 성능이 나옴병합정렬 장단점장점 - 성능이 좋음(O(nlogn))단점 - 이해와 구현이 어려움정렬 - 퀵정렬(Quick Sort)분할 정복 알고리즘으로 재귀를 사용함퀵정렬 설명정렬하기 전에 배열에 있는 숫자 중 하나를 피벗으로 설정해줌leftStartIndex는 피벗보다 큰 값을 만나면 멈춤rightStartIndex는 피벗보다 작은 값을 만나면 멈춤leftStartIndex, rightStartIndex의 값을 스왑해줌서로 지나쳤다면 더이상 진행하지 않음이상태에서 피벗과 rightStartIndex 값 스왑해줌피벗값을 기준으로 오른쪽, 왼쪽을 정렬해줌코드 구현function quickSort(arr, left, right) { if(left <= right) { let pivot = divide(arr, left, right); quickSort(arr, left, pivot - 1); quickSort(arr, pivot + 1, right); } } function divide(arr, left, right) { let pivot = arr[left]; let leftStartIndex = left + 1; let rightStartIndex = right; while(leftStartIndex <= rightStartIndex) { while(leftStartIndex <= right && pivot >= arr[leftStartIndex]) { leftStartIndex++; } while(rightStartIndex <= (left + 1) && pivot >= arr[rightStartIndex]) { rightStartIndex++; } if(leftStartIndex <= rightStartIndex) { swap(arr, leftStartIndex, rightStartIndex); } } swap(arr, left, rightStartIndex); return rightStartIndex; } function swap(arr, index1, index2) { let temp = arr[index]; arr[index1] = arr[index2]; arr[index2] = temp; } let arr = [5, 3, 7, 2, 6, 4, 9, 1, 8]; console.log("==== 정렬 전 ===="); console.log(arr); quickSort(arr, 0, arr.length - 1); console.log("==== 정렬 후 ===="); console.log(arr); 퀵 정렬의 성능피벗이 매번 배열의 반을 가르는 경우O(nlogn)피벗이 배열을 반으로 가르지 않고 한쪽에 쏠리는 경우 - 최악의 경우O(n^2)성능만 보면 병합 정렬이 더 좋다고 볼 수 있는데, 실제로 비교하면 퀵정렬이 더 적은 비교와 더 적은 메모리 공간을 차지하기 때문에 더 좋은 알고리즘으로 평가됨퀵정렬의 장단점 - 병합정렬과 동일동적 프로그래밍 - 메모이제이션재귀의 단점피보나치 수열피보나치 수열 코드function fibonacci(n) { if(n == 0 || n == 1) return n; return fibonacci(n - 2) + fibonacci(n - 1); } console.log(fibonacci(5)); 성능이 좋지 못함 - 반복 계산단점 - 이미 계산했던 것을 다시 또 계산하게 됨메모이제이션재귀의 문제점 해결방법계산 결과를 저장해두고 사용해시테이블 사용피보나치 수열 코드를 메모이제이션을 사용해 수정function fibonacci1(n) { if(n == 0 || n == 1) return n; return fibonacci(n - 2) + fibonacci(n - 1); } function fibonacci2(n) { if(n == 0 || n == 1) return n; if(memo[n] == null) { memo[n] = fibonacci2(n - 2, memo) + fibonacci2(n - 1, memo); } return memo[n]; } let start = new Date(); console.log(fibonacci1(40)); let end = new Date(); console.log("fibonacci1 함수 실행시간 : ${end - start}ms"); let start = new Date(); console.log(fibonacci2(40, {})); let end = new Date(); console.log("fibonacci2 함수 실행시간 : ${end - start}ms"); 메모이제이션 장단점장점성능 O(n)을 보임재귀덕분에 하향식 계산 방식으로 어려운 문제를 간단하게 해결할 수 있음중복 계산을 하지 않아서 속도가 빠름단점메모리 영역을 사용함(ex, 캐시)동적 프로그래밍 - 타뷸레이션상향식 계산 방식으로, 계산에 필요하지 않을 수 있는 값도 미리 계산해 테이블에 저장해둠코드 구현function fibonacci1(n) { if(n == 0 || n == 1) return n; return fibonacci(n - 2) + fibonacci(n - 1); } function fibonacci2(n) { if(n == 0 || n == 1) return n; if(memo[n] == null) { memo[n] = fibonacci2(n - 2, memo) + fibonacci2(n - 1, memo); } return memo[n]; } function fibonacci3(n) { if(n <= 1) return n; let table = [0, 1]; for(let i = 2; i <= n; i++) { table[i] = table[i - 2] + table[i - 1]; } return table[n]; } let start = new Date(); console.log(fibonacci1(40)); let end = new Date(); console.log("fibonacci1 함수 실행시간 : ${end - start}ms"); let start = new Date(); console.log(fibonacci2(40, {})); let end = new Date(); console.log("fibonacci2 함수 실행시간 : ${end - start}ms"); let start = new Date(); console.log(fibonacci3(40)); let end = new Date(); console.log("fibonacci3 함수 실행시간 : ${end - start}ms"); 성능메모이제이션은 여러번의 함수 호출로 메모리 공간에 스택을 차지하고, 메모이제이션을 위한 해시 테이블 공간까지 차지하기 때문에 메모리를 더 많이 사용함타뷸레이션은 적은 메모리 사용임에도 불구하고 빠른 시간을 보임메모이제이션 vs 타뷸레이션메모이제이션재귀를 이용해 문제를 하향식으로 해결함재귀만 이용한다면 중복 계산을 하기 때문에 성능의 문제가 발생했는데 계산 결과를 저장하는 방식으로 단점을 해결함해결하기 힘든 문제를 하향식으로 접근하고, 더 많은 메모리를 이용해 성능을 향상시킴이러한 이유로 분할 정복을 해결할 때 재귀가 더 직관적이라면 메모이제이션을 이용하는 것이 유리함타뷸레이션재귀가 직관적이지 않을 때는 상향식 접근인 타뷸레이션을 이용해 메모리도 절약하고 속도도 빠르게 할 수 있음 '그림으로 쉽게 배우는 운영체제' Section 8, 9, 10Section 8. 가상메모리가상메모리 개요컴퓨터마다 실제 메모리 크기가 다른데, 만약 운영체제나 프로세스가 특정 크기에서 동작하도록 만들어졌다면 그 크기보다 작은 메모리를 가진 컴퓨터에서는 실행되지 않음 → 가상 메모리는 이 문제를 해결함가상 메모리프로세스는 운영체제의 영역이 어디있는지, 물리 메모리의 크기가 얼마나 큰지 몰라도 됨프로세스는 메모리 관리자에게 요청만 하면됨메모리 관리자는 프로세스의 요청이 있으면 그에 맞는 물리 메모리로 연결시켜줌가상메모리의 크기는 이론적으로는 무한대이지만 실제로는 물리 메모리 크기와 CPU의 비트 수로 결정됨 (ex, 32bit CPU(대략 4GB) → 가상 메모리 크기도 4GB가 됨)가상메모리로 프로세스들 실행시키는 방법물리메모리 내용의 일부를 하드 디스크에 있는 스왑영역으로 옮기고, 처리가 필요할 때 물리 메모리로 가져와 실행시키기 때문에 운영체제와 프로세스 5개를 전부 실행시킬 수 있음 동적주소변환(Dynamic Address Translation)메모리 관리자는 물리메모리와 스왑영역을 합쳐서 프로세스가 사용하는 가상주소를 물리주소로 변환함 동적 주소 변환을 거치면 프로세스는 마음대로 사용자 데이터를 물리 메모리에 배치할 수 있음메모리 관리자의 역할물리 메모리를 어떻게 나눌지프로세스를 어디다 배치할지부족한 물리 메모리는 어떻게 처리할지 등등을 위해 복잡한 과정을 거침가상 메모리 시스템의 메모리 할당 방법가상 메모리 시스템에서는 운영체제 영역을 제외한 나머지 영역을 일정한 크기로 나누어서 프로세스에게 할당함할당하는 방식은 메모리 분할방식과 마찬가지로 ‘가변 분할 방식’, ‘고정 분할 방식’으로 나뉨 가변 분할 방식(세그멘테이션)단점 - 외부 단편화고정 분할 방식(페이징)단점 - 내부 단편화각각의 단점을 보완한 ‘세그멘테이션-페이징 혼용기법 ’ 사용세그멘테이션-페이징 혼용기법가상메모리 시스템에서 가상주소는 메모리나 스왑영역 한 곳 중에 위치메모리 관리자는 가상주소와 물리주소를 일대일 매핑 테이블로 관리함 세그멘테이션(배치정책)가변 분할 방식을 이용하는 세그멘테이션 기법프로그램은 함수나 모듈등으로 세그먼트 구성프로그램(사용자) 관점 메모리 - 코드, 데이터, 힙, 라이브러리, 스택 각각 구성(인접할 필요 없음)프로세스 관점 메모리 - 코드, 데이터, 힙, 스택 영역을 서로 인접한 것처럼 바라봄논리주소사용자, 프로세스, CPU가 바라보는 주소실제 물리주소로 변환은 중간에서 메모리 관리자(MMU)가 해줌메모리 관리자가 논리주소 → 물리주소 변환 방법메모리 관리자가 가지고 있는 세그멘테이션 테이블에 Base Address, Bound Address(Segment 크기) 정보가 저장되고 이걸 이용해 물리 메모리 주소를 계산함운영체제는 컨텍스트 스위칭을 할 떄마다 메모리 관리자 내에 Segment Table Base Register를 해당 프로세스의 것으로 값을 바꿔줘야함 → 굉장히 무거운 동작논리주소가 Bound Address보다 작다면, 논리주소 + Base Address 로 물리주소를 구함논리주소가 Bound Address보다 크다면, 메모리를 침범했다고 생각하고 에러를 발생세그멘테이션 장점메모리를 가변적으로 분할할 수 있고, 코드 영역, 데이터 영역, 스택 영역, 힙 영역을 모듈로 처리할 수 있음 → 공유와 각 영역에 대한 메모리 접근보호가 편리함세그멘테이션 단점가변 분할 방식의 단점인 “외부 단편화”가 발생함페이징(배치정책)고정분할방식을 이용한 페이징세그멘테이션 기법은 외부 단편화 문제가 있기 때문에 이를 해결하기 위해 고안됨페이징메모리를 할당할 때 정해진 크기의 페이지로 나눔모든 페이지는 크기가 같기때문에 관리가 편하고, 일정한 크기로 나눴기 때문에 외부 단편화 현상이 일어나지 않음논리주소공간에서의 페이징 → 페이지물리주소공간에서의 페이징 → 프레임 페이징의 주소변환 방법메모리 관리자가 “페이지 테이블”을 통해 CPU에서 전달받은 논리주소가 몇번 페이지, 오프셋은 얼마인지 알아냄메모리 관리자 내에 Page Table Base Register(PTBR)를 이용해서 물리 메모리에 있는 페이지 테이블을 찾고, 페이지 번호를 인덱스로 프레임 번호를 알아내고, 오프셋을 이용해 물리주소로 변환을 함페이지 테이블에 Invalid로 표시되어 있으면 스왑영역, 즉 하드디스크레 저장되어 있다는 의미임PTBR은 운영체제가 컨텍스트 스위칭을 할 때마다 해당 프로세스의 것으로 업데이트 해줌 세그멘테이션 vs 페이징 차이점페이지의 크기가 다름세그멘테이션은 프로세스마다 크기가 달라 Bound Address를 가지고 있지만, 페이징은 모든 페이지의 크기가 동일해서 크기를 표현하는 Bound Addresss는 필요하지 않음페이징은 이런 특성때문에 외부단편화는 발생하지 않지만 내부단편화가 발생함 (정해진 크기의 페이징보다 프로세스의 정보가 작으면 그만큼 공간이 낭비됨)세그멘테이션의 단점과 비교하면 많은 고간이 낭비되는게 아니라서 심각하게 생각하지 않음세그멘테이션은 논리적인 영역별로 세그먼트를 나눔(코드, 데이터, 스택, 힙 영역), 그러나 페이징은 페이지의 크기가 고정되어 있어 논리적인 영역별로 나누는 것이 아니라 페이지로 나누기 때문에 논리적인 영역을 나눌 수 없음 그래서 특정 영역만 공유하거나 권한을 부여하는게 더 어려움페이징에서 가장 신경써야하는 것은 페이지 테이블 크기임각 프로세스마다 페이지 테이블을 가지고 있는데 프로세스가 많아질수록 페이지 테이블도 많아지기 때문에 프로세스가 실제로 사용할 수 있는 메모리 영역이 줄어듦실제로 메모리 관리자가 참조하는 페이지 테이블도 물리 메모리의 운영체제 영역에 저장되어 있기 때문에 페이지 테이블 크기가 너무 크면 사용자 영역이 부족하게 됨 → 페이지 테이블의 크기를 적절하게 유지하는 것이 굉장히 중요함페이지드 세그멘테이션(배치정책)페이징과 세그멘테이션의 각각의 장점을 취한 방식 → 새로운 단점이 생기기도 함세그멘테이션 장점가변 분할 방식이라서 코드 영역, 데이터 영역, 스택 영역, 힙 영역을 세그먼트로 나눠서 관리할 수 있음그에 따라 다른 프로세스와 공유하기도 편하고, 각 영역에 대한 메모리 접근보호를 하기가 쉬움페이징 장점고정분할 방식으로 메모리를 효율적으로 관리할 수 있음메모리 접근 권한메모리의 특정 번지에 부여된 권한으로 읽기(Read), 쓰기(Write), 실행(Execute) 세 가지가 있음 프로세스는 코드 여역, 데이터 여역, 스택 영역, 힙 영역이 있는데 각 영역마다 접근 권한이 있음 코드 영역프로그램 그 자체이기 때문에 수정되면 안되므로, 읽기와 실행 권한만 있음데이터 영역일반변수, 전역변수, 상수로 선언한 변수가 저장되기 때문에 읽기 권한이 있고, 쓰기 권한은 있거나 없거나 함 실행권한은 없음스택, 힙 영역읽기, 쓰기 권한이 있고, 실행권한은 없음메모리 접근권한에 대한 검사는 가상주소에서 물리주소로 변환될 때마다 일어나는데, 만약 권한을 위반하면 에러를 발생시킴 페이지드 세그멘테이션세그멘테이션 기법 - 세그멘테이션 테이블은 Base Address와 Bound Address로 구성됨페이징 기법 - 페이지 테이블은 프레임 번호로 구성됨 위의 둘을 혼합해 페이지드 세그멘테이션으로 만듦 (각각의 역할은 이름만 바꼈을 뿐 달라진 것은 없음)세그멘테이션 테이블에 권한 비트를 추가함Base Address는 페이지 넘버로 바뀜Bound Address는 이 세그먼트 페이지 개수로 바뀜 페이지드 세그멘테이션의 단점은 물리메모리에 접근하기 위해서 메모리에 접근을 두 번해야 된다는 것첫번째, 세그멘테이션 테이블을 참조할 때두번째, 페이지 테이블을 참조할 때 일어남위의 단점 때문에 운영체제는 페이징과 페이지드 세그멘테이션 기법을 적절히 섞어서 사용함디맨드 페이징(가져오기 정책)프로세스가 실행될 때, 프로세스를 이루고 있는 코드영역, 데이터영역, 힙영역, 스택영역과 같은 모듈이 모두 메모리에 올라와 실행된다고 알고 있음하지만 실제로는 모든 모듈이 메모리에 올라오는 것이 아니라 필요한 모듈만 올라와서 실행됨도널드 커누스의 발견 - 90:10 법칙90%의 시간이 10% 코드에서 보내는 것 → 지역성 이론이라고 함지역성(두가지)공간의 지역성현재 위치에서 가까운 데이터에 접근할 확률이 높다는 것시간의 지역성최근 접근했던 데이터가 오래전에 접근했던 데이터보다 접근할 확률이 높음goto문 - 지역성 이론에 따라 성능이 좋지 않기 때문에 쓰지 않는 것을 추천지역성 이론은 조만간 쓰일 데이터만 메모리에 올리고 당분간 필요하지 않을 것 같은 데이터는 스왑영역으로 보내 성능을 향상시킴 디맨드 페이징은 조만간 필요할 것 같은 데이터를 메모리로 가져오고 쓰이지 않을 것 같은 데이터는 스왑영역으로 이동시키는 정책ex, 포토샵포토샵은 본 프로그램 외에도 이미지에 효과를 주는 외부 필터들이 있는데, 이 필터들을 포토샵과 같이 메모리에 모두 올리면 메모리를 많이 차지해서 프로그램이 더 무거워짐그래서 본 프로그램만 메모리에 올리고 외부 필터들은 사용자의 요청이 있을 때만 메모리로 가져오는 것이 메모리도 절약되고, 메모리를 효율적으로 관리할 수 있고, 프로세스의 응답속도도 빨라짐 메모리 계층구조메모리는 레지스터, 캐시, 메인 메모리, 보조저장장치로 나눌 수 있음메인 메모리에 접근하는 시간 레지스터CPU 내에 존재하고, CPU의 한사이클에 접근할 수 있어서 굉장히 빠름캐시CPU의 수 사이클에서 수십 사이클에 접근 가능메인 메모리CPU의 수백 사이클에 접근 가능보조저장장치(HDD, SSD)CPU의 수백만 사이클에 접근 가능디맨드 페이징은 스왑영역을 보조저장장치에 저장하는데, 성능향상을 위해서는 스왑영역으로 데이터를 이동시키는 것을 최소화 시켜야 함가상 메모리의 크기 = 물리 메모리 크기 + 스왑영역임스왑인, 스왑아웃 스왑인 - 스왑영역에서 물리메모리로 데이터를 가져오는 것스왑아웃 - 물리메모리에서 스왑영역으로 데이터를 내보내는 것메모리 관리자는 페이지 테이블을 참조해서 물리 메모리가 있는 프레임을 알아내거나 스왑영역의 위치를 알아내야 하는데, 이를 위해 페이지 테이블에는 여러가지 비트가 있음페이지 테이블을 이루고 있는 한 행을 페이지 테이블 엔트리(PTE)라고 부름 페이지 테이블 엔트리(PTE) 접근 비트페이지가 메모리에 올라온 후 데이터에 접근이 있었는지 알려주는 비트메모리에 읽거나 실행 작업을 했다면 1로 바뀌게 됨변경비트페이지가 메모리에 올라온 후 데이터의 변경이 있었는지 알려주는 비트메모리에 쓰기 작업을 했으면 1로 바뀌게 됨유효비트페이지가 물리 메모리에 있는지 알려주는 비트만약 유효비트가 1이라면 페이지가 스왑영역에 있고, 0이라면 물리 메모리에 있다는 의미임읽기, 쓰기, 실행 비트권한 비트로 해당 메모리에 접근권한이 있는지 검사하는 비트프로세스가 가상 메모리에 접근요청을 했을 때 메모리 관리자는 페이지 테이블을 보고 물리 메모리의 프레임을 찾아냄만약 물리 메모리에 없다면 Page Fault라는 인터럽트를 발생시킴Page Fault가 발생하면 보조저장장치의 스왑영역에 접근하게 되고 해당 프로세스는 대기상태가 됨스왑영역에 있는 데이터가 메모리에 올라가는 작업을 시작하고, 메모리에 올라갔다면 대기상태에 있던 프로세스는 다시 실행하게 됨물리 메모리와 스왑영역에서 어떻게 참조되는가(세가지)스왑이 필요없는 경우 ex, 프로세스가 페이지 0을 요청페이지 테이블의 0번 인덱스를 살펴보면 유효비트 0, 프레임 넘버 1 → 해당 주소가 물리메모리의 1번 프레임물리 메모리에 있는 1번 프레임에 접근해 데이터를 참조함스왑영역에 있는 데이터를 참조하는 경우ex, 프로세스가 페이지 2번을 요청 페이지 테이블의 2번 인덱스를 살펴보면, 유효비트가 1이고 프레임 넘버가 2임 → 페이지가 스왑영역 2번에 있다는 뜻물리메모리에 적절히 빈 공간을 찾음스왑영역 2번에 저장된 C를 물리메모리 3번 프레임으로 가져오고페이지 테이블에서 해당 엔트리의 유효비트를 0으로, 프레임 넘버를 3으로 수정함프로세스에게 데이터를 참조하게 해줌물리메모리가 꽉찼을 때 스왑영역에 있는 데이터를 참조하는 경우ex, 프로세스가 페이지 1번을 요청했다고 가정 페이지 테이블 1번 인덱스를 살펴보면, 유효비트 1, 프레임 넘버 0 → 페이지가 스왑영역 0번에 있음물리메모리로 가져오기 위해 적절한 빈공간을 찾지만 꽉 차서 여유가 없음현재 물리 메모리에서 필요하지 않다고 판단하는 영역을 스왑영역으로 옮김A가 필요하지 않다고 가정하고 스왑영역 3번으로 옮김페이지 테이블에서 0번 인덱스의 유효비트를 1, 프레임 넘버를 3으로 변경물리메모리 빈공간이 된 1번으로 B를 가져옴페이지 테이블에서 1번 인덱스의 유효비트를 0으로, 프레임 넘버를 1로 수정함프로세스에게 데이터를 참조하게 해줌스왑인(스왑영역 → 물리메모리), 스왑아웃(물리메모리 → 스왑영역) 시, 어떤게 적절한지는 운영체제가 판단함 → 페이지 교체 알고리즘페이지 교체정책메모리가 꽉찼을 때, 어떤 페이지를 스왑영역으로 보낼지 결정하는 정책임프로세스는 데이터 접근을 위해 메모리를 참조하는데, 해당 데이터가 메모리에 없으면 Page Fault가 발생함Page Fault가 발생하면, 해당 페이지를 스왑영역에서 메모리로 불러들여야하는데 메모리가 꽉차서 공간이 없다면 메모리에 있는 페이지 중 하나를 선택해서 스왑영역으로 옮겨야함메모리에 있는 페이지를 스왑영역으로 옮길 때 어떤 페이지를 선택할지 결정하는 정책을 페이지 교체 정책이라고 부르고, 페이지 교체 정책에는 여러가지가 있음페이지 교체 정책의 방법들무작위로 선택하는 방법(Random)지역성을 고려하지 않기 때문에 자주 사용되는 페이지가 선택될 때도 있어 성능이 별로 좋지 않음그래서 거의 사용되지 않음메모리에 들어온지 가장 오래된 페이지를 선택하는 방법(FIFO)자주 쓰이는 페이지가 먼저 들어왔다는 이유로 해당 페이지가 교체되면 공평하지 않음위의 단점이 있지만 구현이 간단하고 성능도 꽤 괜찮아서 조금 변형해서 많이 쓰임앞으로 가장 오랫동안 쓰이지 않을 페이지를 선택하는 방법(Optimum)사실상 구현이 불가능한 이론적인 선택방법구현이 불가능해서 필요가 없을 것 같지만, 다른 알고리즘과 성능 비교를 할 때 참조용으로 쓰임최근에 가장 사용이 적은 페이지를 선택하는 방법(LRU - Least Recently Used)지역성 이론의 시간의 지역성에 따르면 최근 사용한 데이터가 앞으로도 사용될 확률이 높기 때문에 최근에 가장 사용을 적게한 페이지가 앞으로도 사용될 확률이 적다는 결론이 나옴실제로도 Optimum 알고리즘에 근접한 성능을 보임그러나 프로그램이 지역성을 띄지 않을땐 성능이 떨어지게됨페이지 테이블 엔트리는 여러개의 비트와 페이지 넘버가 저장되는데, 이곳에 시간을 기록하려면 비트가 많이 필요하게됨많은 비트를 준비하기 어려우므로 실제 LRU를 구현할 때는 접근비트를 이용해서 LRU에 근접하게 구현함Optimum vs FIFO vs LRU 비교 ex, 페이지가 A B C A C D A D C A B 순서대로 요청되는 상황 세 방법 모두 메모리가 비어있기 때문에 처음 요청에서는 전부 Page Fault가 발생함A 요청 들어옴세 알고리즘 모두 Page Fault가 일어나지 않음C 요청 들어옴세 알고리즘 모두 Page Fault가 일어나지 않음D 요청 들어옴Page Fault 발생Optimum뒤에 들어오는 요청을 훑어봄페이지 B가 가장 사용되지 않을 것을 알기 때문에 페이지 B를 스왑영역으로 옮기고, B가 있던 자리에 D를 가져옴FIFO먼저 들어온 페이지가 먼저 나가기 때문에 가장 먼저 들어온 페이지 A를 스왑영역으로 보내고, A가 있던 자리에 D를 가져옴LRU최근에 가장 사용이 적은 페이지가 나가기 때문에 최근에 들어온 페이지의 참조 수를 계산함A 2번, B 1번, C 2번으로 B가 가장 덜 사용됐으니 B를 스왑영역으로 옮기고 B가 있던 자리에 D가 들어옴빌레이디의 역설(Belady’s Anomaly)Page Fault를 줄이려고 메모리를 더 늘려서 프레임 수를 늘렸는데, 오히려 Page Fault가 더 많이 발생하는 현상→ FIFO의 가장 큰 문제임FIFO에서만 발생하며 LRU에서는 발생하지 않음LRU 문제점시간을 기록해야하는 LRU는 구현이 힘듦시간을 기록할 bit가 많이 필요많은 bit가 있어도 시간이 아주 오래 지난다고 가정하면 어쩔수없이 오버플로우가 발생 → 오버플로우로 값이 초기화되면서 시간을 올바르게 표현할 수 없게됨클락 알고리즘 LRU 알고리즘과 유사하게 구현하는 방법접근비트 하나만 이용일정 시간 간격마다 모든 페이지의 접근 비트를 0으로 초기화함접근비트의 초기값은 0으로 설정되어 있고, 만약 페이지가 참조되었다면 1로 설정됨페이지를 원형으로 연결함스왑영역으로 옮길 페이지를 포인터로 가르키는데, 이 포인터를 클락 핸드라고 부름클락 핸드는 시계방향으로 돌게됨만약 Page Fault가 발생해서 스왑영역으로 보내야하는 상황이 나오면, 클락 핸드는 현재 참조하고 있는 페이지의 접근비트를 봄만약 접근비트가 1이라면 해당 접근비트를 0으로 바꾸고, 클락핸드가 다음 페이지를 가르킴이렇게 반복하다가 접근비트가 0인 페이지를 발견하면, 해당 페이지를 스왑영역으로 보냄향상된 클락 알고리즘(Enhanced Clock Algorithm)이 알고리즘은 접근비트만 이용하는 것이 아니라 변경비트까지 봄스왑 영역으로 보내지는 순위가 가장 높은 것은 접근비트가 0이고, 변경비트도 0인 페이지임그 다음으로 접근비트가 0, 변경비트가 1인 페이지임그 다음으로 접근비트가 1, 변경비트가 0인 페이지임마지막으로 접근비트가 1, 변경비트가 1인 페이지가 교체됨FIFO를 사용하는 경우LRU에서는 접근비트를 이용하는데, 하드웨어적으로 접근비트를 지원하지 않는 시스템에서는 FIFO를 이용할 수 밖에 없음어쩔 수 없이 FIFO를 이용하기 위해 성능을 높이는 방법을 고안함2차 기회 페이지 교체 알고리즘FIFO방식에서 자주 사용하는 페이지에게는 또 한번의 기회를 줌FIFO방식과 동일하게 동작하지만, 만약 Page Fault없이 페이지 접근에 성공했다면 해당 페이지를 큐의 맨 뒤로 이동시켜 수명을 연장시켜주는 방식이 알고리즘은 LRU보다는 안좋고, FIFO보다는 좋음스레싱과 워킹셋CPU 스케줄링CPU 사용률을 높이는 것이 목표CPU 사용률을 높이기 위해서는 동시에 실행하는 프로세스의 수, 멀티프로그래밍의 정도를 올리는 것동시에 실행하는 프로세스의 수가 늘어나면, 어떤 프로세스가 I/O작업으로 CPU를 사용할 수 없을 때 다른 프로세스로 컨텍스트 스위칭을 해서 CPU 사용률을 높일 수 있음CPU 사용률을 위해 멀티프로그래밍의 정도를 높였으면, 프로세스들이 필요로하는 공간이 있기때문에 물리메모리에 프레임을 할당해야함물리메모리의 크기는 한계가 있기 때문에 모든 프로세스의 모든 프레임을 물리메모리에 올릴 수 없고, 일부는 스왑영역에 저장됨멀티프로그래밍 정도가 늘어나는 경우에 문제가 나타남멀티프로그래밍 정도가 늘어나면 제한된 물리메모리에 모든 프로세스를 올려야하고, 당장 실행되는 프레임을 제외한 나머지 프레임들은 스왑영역에 저장되고 Page Fault가 많이 발생하게 됨CPU가 작업하는 시간보다 스왑작업의 시간이 더 길어지고, CPU 사용률은 떨어지게됨CPU 스케줄러는 CPU 사용률이 낮아지면, 더 많은 프로세스를 메모리에 올리게되고, 이렇게 반복하다보면 어느새 CPU 사용률이 0에 가깝게 떨어지게됨스레싱CPU 사용률을 높이려했지만 오히려 더 떨어지는 상황근본적인 원인은 물리메모리의 크기가 부족한 것하드웨어적으로 해결하려면 메모리 크기를 늘리면 됨그러나 4GB 램에서 16GB 램으로 올려도 성능향상을 느끼기 힘듦현재 메모리가 프로세스들이 작업을 하는데 충분한 크기라서 스레싱이 발생하지 않는다면 크기를 늘려도 별 다른점이 없기 때문임운영체제가 스레싱을 소프트웨어적으로 해결하기 위한 방법한 프로세스가 실행될 때 너무 많은 페이지를 할당하면 다른 프로세스가 사용할 페이지가 줄어들기 때문에 효율이 떨어지게됨반대로 너무 적은 페이지를 할당하면 빈번한 Page Fault가 발생하고, 스왑요청이 많아 스레싱이 발생하게됨이를 해결하기 위한, 프로세스가 실행되는 동안 해당 프로세스에게 맞는 적절한 페이지 수 결정 방법프로세스가 실행되면 일정량의 페이지를 할당 후, 만약 Page Fault가 발생하면 더 많은 페이지를 할당하고, 반대로 Page Fault가 너무 적게 발생하면 페이지를 과하게 할당해 메모리가 낭비되는 것이라고 판단하고 페이지를 회수함어떤 페이지를 유지할 것인지 결정 방법지역성 이론을 따름현재 메모리에 올라온 페이지는 다시 사용할 확률이 높기 때문에 하나의 세트로 묶어서 메모리에 올림 → 워킹셋워킹셋은 프로세스가 준비상태에서 실행상태가 되는 컨텍스트 스위칭을 할 때 사용됨Section 9. 입출력주변장치(I/O 디바이스, 저장장치)주변장치 종류그래픽카드, 하드디스크, SSD, 키보드, 마우스 등이 있음 주변장치들은 메인보드에 있는 버스로 연결됨버스 Address 버스, Data 버스, Control 버스로 이루어져 있음I/O 디바이스는 이 세가지 버스를 따로 받을 수 있음외부 인터페이스각 하드웨어에 맞게 존재함각종 레지스터장치의 상태와 데이터를 보관할 수 있음입출력 작업을 할 때 데이터를 저장하는 역할을 함값들은 CPU가 사용하기위해 메모리로 이동되기도 함데이터의 전송단위에 따른 주변장치 분류데이터의 전송단위가 캐릭터(글자)인지, 블록인지에 따라 나뉨캐릭터 디바이스마우스, 키보드, 사운드카드, 직별렬포트 등데이터 전송 단위가 캐릭터(글자)로 상대적으로 크기가 작음블록 디바이스하드디스크, SSD, 그래픽카드 등데이터 전송 단위가 블록(범위)로 상대적으로 크기가 큼각 장치 세부 설명버스 예전에는 주변장치들을 하나의 버스로 연결해서 사용함CPU가 작업을 하다가 I/O 명령을 만나면 직접 입출력장치에서 데이터를 가져왔는데 입출력중에는 다른 작업을 하지 못했기 때문에 CPU사용률이 떨어짐이를 해결하기 위해 입출력 제어기(I/O Controller)와 여러개의 버스가 추가됨 CPU는 I/O 명령을 만나면 입출력 제어기에게 입출력작업을 맡기고 다른 작업을 실행함입출력 제어기시스템 버스, 입출력 버스로 구분하여 두 개의 채널을 가지고 있음시스템 버스고속으로 작동하는 CPU와 메모리가 사용입출력 버스주변장치가 사용입출력 버스는 세부적으로 느린장치와 빠른장치를 구분하기 위해 다시 고속 입출력 버스, 저속 입출력 버스 두 개의 채널로 나뉨 → 느린장치와 빠른장치로 구분 해 속도차이로 인한 병목현상을 해결함그래픽 카드그래픽 카드가 다루는 데이터는 매우 대용량이라 고속 입출력 버스로도 감당이 안됨그에 따라 그래픽 카드는 입출력 버스에 있지 않고, 시스템 버스에 바로 연결해 사용함입출력 제어기입출력 제어기는 여러 주변장치를 처리하는데 입출력 버스에서 온 데이터를 메모리로 옮김메모리는 CPU의 명령으로 움직이기 때문에 입출력 제어기가 메모리에 접근하기 위해서는 CPU가 필요함 입출력 제어기가 CPU의 도움이 필요없도록 DMA(Direct Memory Access - 직접 메모리 접근) 제어기가 추가됨입출력 제어기는 DMA로 데이터를 직접 메모리에 저장하거나 가져올 수 있음Memory Mapped I/OCPU와 DMA가 사용하는 메모리가 겹치지 않도록 CPU가 사용하는 메모리 영역과 DMA가 사용하는 메모리 영역을 나눔마우스/키보드마우스볼 마우스회전을 감지해서 움직임을 처리하는 방식광학 마우스아래쪽에 작은 카메라가 표면으로 초당 1500회가 넘는 사진을 찍어 마우스의 디바이스 컨트롤러 내 DSP(Digital Signal Processor)로 보냄DSP는 이 사진을 분석해 마우스의 X축 좌표와 Y축 좌표 움직임을 캐치함DSP가 마우스의 움직임과 클릭같은 데이터를 감지하면, 디바이스 컨트롤러는 CPU에게 인터럽트를 보내고, 마우스 드라이버가 동작해서 데이터를 읽어감마우스 드라이버는 운영체제에게 이벤트 신호를 주는데, 운영체제는 이 이벤트 Foreground 애플리케이션으로 전달해주고 해당 애플리케이션은 받은 마우스 이벤트 처리를 함키보드사용자가 키보드 버튼을 누르면 키보드의 디바이스 컨트롤러가 어떤 키를 입력 받았는지 알아냄CPU에게 인터럽트를 보내고 키보드 드라이버는 운영체제에게 이벤트를 보냄운영체제는 Foreground 애플리케이션으로 이 이벤트를 전달해주고, 애플리케이션에서 해당 키에 맞는 동작을 수행함하드디스크/Flash Memory(SSD)하드디스크 구조 spindleplatter여러개의 트랙으로 구성됨표면에 자성이 있어 N극을 띄면 0, S극을 띄면 1로 인식함보통 하드디스크의 플래터 수는 2개 이상임실린더(cylinder)트랙은 다시 여러개의 섹터로 나뉘는데, 섹터가 하드디스크의 가장 작은 단위임 disk Arm읽기/쓰기 헤드로 플래터의 표면을 읽음read/write head헤드는 disk Arm에 고정되어 있기 때문에 모든 헤드는 항상 같이 움직임헤드가 움직이면 이 헤드들은 여러 개의 플래터를 가리키게 되는데, 이때 여러개의 플래터에 있는 같은 트랙의 집합을 실린더(cylinder)라고 부름하드디스크에서 데이터 읽어오는 예시유저프로세스가 하드디스크의 특정 섹터에 접근을 위해 요청을 보냄 (ex, 실린더 C로 가서 트랙 B에 있는 섹터 D를 읽어라)디스크암은 헤드를 실린더 C로 이동시키는데, 이를 Seek라고 부름헤드를 실린더로 이동시키는데 걸리는 시간을 Seek Time이라고 부름 → 이것때문에 하드디스크가 굉장히 느림트랙 B의 섹터 D가 헤드에 닿을 때까지 스핀들을 회전시키고, 헤드에 섹터 D가 읽히면 작업이 끝남Flash Memory요즘은 하드디스크보다 Flash Memory를 더 많이 사용함데스크탑에는 Flash Memory 이점으로 많은 사람이 SSD를 사용함핸드폰, 테블릿은 하드디스크를 넣을 큰 공간이 없어서 Flash Memory를 사용함하드디스크 vs Flash Memory하드디스크기계적으로 헤드를 움직여 속도가 많이 느리고 소음도 남자기적으로 처리하는 하드디스크는 자석을 갖다대면 데이터가 손상됨스핀들처럼 회전축같은 것들이 있어서 충격에 매우 약함Flash Memory전기적으로 읽기 때문에 굉장히 빠르고 조용함자석을 갖다대도 데이터가 안전함충격에 약하지 않음그러나 특정한 지점에 데이터를 썼다면 덮어쓰기가 불가능 하다는 단점이 있음 똑같은 지점에 데이터를 쓰려면 기존에 있던 데이터를 지우고 새로 써야하는데, Flash Memory는 지우기 가능한 횟수가 정해져있음(읽기/쓰기를 반복하면 망가져 사용할 수 없음) Section 10. 파일시스템파일과 파일시스템파일들을 하드디스크나 SSD와 같은 저장장치에 저장됨사용자가 운영체제에게 요청 시, 운영체제가 하드디스크에 안전하게 저장함운영체제는 파일 관리를 위해 파일 관리자를 둠 → 파일 시스템파일 시스템파일 관리자는 가상메모리에서 메모리 관리자가 페이지 테이블을 이용해서 가상주소를 물리주소로 변환하는 것처럼 파일 테이블을 이용해서 파일을 관리함파일 시스템의 기능파일과 디렉토리를 만듦파일과 디렉토리의 수정, 삭제를 함다른 사용자로부터 파일을 보호하기 위해 접근권한을 관리함 (요즘 운영체제는 다중 사용자 기능을 지원하기 때문에 파일을 보호하기 위해서 꼭 필요한 기능임)파일의 내용이 손상되지 않도록 무결성을 보장함예기치 못한 사고로부터 백업과 복구를 함파일을 암호화해 파일을 보호함파일시스팀 전송단위하드디스크와 Flash Memory는 블록 디바이스임 따라서 전송단위가 블록임저장 단위는 블록이지만, 사용자는 바이트 단위로 파일에 접근이 가능해야하기 때문에 파일관리자가 중간에서 관리해줌파일확장자유닉스 운영체제에는 파일확장자가 없음윈도우즈는 파일확장자가 있음파일 내부 구성헤더, 데이터로 이루어져있음헤더파일의 속성들이 담겨 있음파일 디스크립터(File Descriptor)운영체제는 파일을 관리하기 위해 정보를 보관하는 파일제어블록(File Control Block, FCB)을 가지고 있는데, 이를 파일 디스크립터(File Descriptor)라고 부름파일 디스크립터는 파일마다 독립적으로 존재하고, 저장장치에 존재하다가 파일이 오픈되면 메모리로 이동함파일 디스크립터는 파일시스템(운영체제)이 관리하고, 사용자가 직접 참조할 수는 없음사용자는 파일시스템이 건내준 파일 디스크립터로 파일에 접근할 수 있음파일 종류 분류파일은 데이터의 집합으로, 데이터의 집합을 어떻게 구성하느냐에 따라 종류를 나눌 수 있음순차파일구조파일의 내용이 연속적으로 이어진 상태 (ex, 카세트테이프)파일시스템이 사용자에게 전달해준 파일디스크립터는 파일의 맨 앞에 위치해서 사용자가 쓰거나 읽기를 시작하면 처음부터 진행함파일의 다른영역으로 가고 싶을 때 - lseek함수를 이용해 파일디스크립터 위치를 옮김 장점모든 데이터가 순서대로 기록되기 때문에 공간의 낭비가 없고 구조가 단순함단점특정지점에 바로 이동이 어려워 데이터를 삽입하거나 삭제하려면 탐색하는데 시간이 많이 걸림직접파일구조저장하려는 데이터를 해시함수를 통해 저장위치를 결정하는 파일구조자료구조에서 해시 테이블이라는 이름으로 불리는 방식json도 이 방식임 장점해시함수를 이용하기 때문에 데이터 접근이 굉장히 빠르다는 것단점해시함수의 선정이 굉장히 중요하기 때문에 해시함수를 잘 골라야한다는 점과 저장공간이 낭비될 수 있다는 점인덱스파일구조순차접근과 직접접근 방식의 장점을 취한 것으로 두가지 방식 모두 가능함ex, 음악재생 프로그램의 재생목록 디렉토리디렉토리란?파일을 하나의 공간이 아닌, 관련있는 파일을 모아둘 수 있게 하기 위함한 개 이상의 파일을 가질 수 있고, 자식 디렉토리도 가질 수 있음디렉토리는 여러층으로 구성됨최상위에 있는 디렉토리 - 루트 디렉토리유닉스, 리눅스에서는 루트 디렉토리를 “/”로 표시함, 디렉토리 별 구분을 위해서도 “/”를 사용함윈도우즈는 루트 디렉토리를 파티션 이름으로 사용하는데, 보통 “C:”으로 표시함윈도우즈는 디렉토리와 디렉토리 구분을 “\”로 함디렉토리도 파일임. 단지 일반 파일에는 데이터가 저장되어 있고, 디렉토리에는 파일 정보가 저장되어 있음 디렉토리 구조과거 - 루트 디렉토리에만 하위 디렉토리 존재했었음파일이 많아지면서 다단계 디렉토리구조가 등장함다단계 디렉토리구조어떤 디렉토리에서도 하위 디렉토리를 만들 수 있는 트리구조운영체제는 트리구조에서 순환이 생기는데, 바로가기 기능이 있기 때문임 파일과 디스크파일은 메모리와 비슷한데, 페이징과 같이 전체 디스크 공간을 일정한 크기로 나누고, 그 공간에 주소를 할당해 관리함일정한 크기로 나눈 공간을 파일시스템에서는 블록이라고 함 (메모리에서는 페이지라고 부름)한 블록의 크기는 1~8KB파일시스템은 파일정보를 파일테이블로 관리하는데, 파일이 시작하는 블록의 위치정보도 담겨있음파일 내 블록 분류여러 개의 블록들로 이루어져 있는 하나의 파일에서, 그 블록들이 어떻게 연결되었는지에 따라 분류됨연속할당파일을 구성하는 블록들을 디스크에 연속적으로 저장하는 방식임파일의 시작 블록만 알면 파일의 전체를 찾을 수 있음메모리에서 세그멘테이션 기법처럼 외부 단편화가 발생하기 때문에 실제로 사용되지 않는 방식임불연속할당디스크에 비어있는 공간에 데이터를 분산해 저장하는 방식분산된 블록은 파일시스템이 관리함연결할당, 인덱스 할당이 있음연결할당파일에 속한 데이터를 연결리스트로 관리함파일테이블에는 시작 블록에 대한 정보만 저장하고, 나머지는 연결리스트를 이용해 다른 블록에 접근하는 방식 인덱스할당테이블의 블록포인터가 데이터 블록에 직접 연결하는 것이 아니라 데이터들의 인덱스를 가지고 있는 인덱스 블록을 연결함 인덱스 할당은 데이터가 많아서 테이블이 꽉 찬 경우 인덱스 블록을 더 만들어서 연결하기 때문에 테이블을 확장할 수 있음파일의 크기가 작다면, 데이터를 바로 참조하는 블록 포인터를 이용하고, 파일의 크기가 크다면 간접 포인터를 이용해 많은 데이터에 접근할 수 있음만약 더 큰 데이터가 필요하다면, 이중 간접 포인터, 삼중 간접 포인터를 이용할 수 있음 (i-node라는 이름으로 유닉스와 리눅스에서 많이 사용되고 있음)free block list빈 공간을 찾기위해 매번 모든 메모리를 찾지 않기 위해 빈 공간을 모아둠만약 특정 파일 삭제 시, 파일시스템은 파일의 모든 정보를 지우는 것이 아니라 파일 테이블의 헤더를 삭제하고 free block list에 추가함 회고일주일 동안 스스로 칭찬하고 싶은 점, 아쉬웠던 점, 보완하고 싶은 점칭찬하고 싶은 점 : 이번주 강의가 조금 어렵게 느껴졌지만 포기하지 않고 끝까지 잘 학습한 점아쉬웠던 점 : 이번주에 회사일이 많아서 내용 중 이틀 치를 몰아서 듣게 되었는데 충분한 학습을 하지 못했다는 아쉬움이 남음보완하고 싶은 점 : 중간중간 이해가 안되는 부분들이 있었는데, 그 부분을 반복학습 해야겠습니다🙌다음주에는 어떤 식으로 학습하겠다는 스스로의 목표수료식 전까지 따로 스터디 스케쥴이 없는 것 같으니 이번주 강의를 다시한번 봐야겠습니다💪

알고리즘 · 자료구조알고리즘자료구조운영체제

minme9055

[인프런 워밍업 클럽 2기 CS] 3주차 발자국

운영체제세그멘테이션(배치정책)메모리를 논리적 단위(세그먼트)로 분할각 세그먼트는 다양한 크기 가능외부 단편화 문제 발생 가능페이징(배치정책)메모리를 동일한 크기의 페이지로 분할물리 메모리와 가상 메모리 간 매핑내부 단편화 발생 가능, 외부 단편화 해결페이지드 세그멘테이션(배치정책)세그멘테이션과 페이징 결합세그먼트를 페이지 단위로 나눔유연성과 효율성 향상디맨드 페이징(가져오기 정책)필요한 페이지만 메모리에 로드페이지 부재 시 디스크에서 가져옴메모리 사용 효율성 증가페이지 교체정책FIFO, LRU, LFU 등 다양한 알고리즘새 페이지 로드 시 어떤 페이지를 교체할지 결정페이지 부재율 최소화 목표스레싱과 워킹셋스레싱: 과도한 페이지 교체로 성능 저하워킹셋: 프로세스가 자주 참조하는 페이지 집합워킹셋 관리로 스레싱 방지주변장치(I/O 디바이스, 저장장치)CPU, 메모리 외 하드웨어 장치입력, 출력, 저장 기능 수행인터럽트 기반 동작마우스/키보드사용자 입력 장치이벤트 기반 동작인터럽트 처리 필요하드디스크/Flash Memory(SSD)하드디스크: 기계식, 대용량, 저렴SSD: 전자식, 고속, 고가비휘발성 저장 장치파일과 파일시스템파일: 관련 데이터의 논리적 집합파일시스템: 파일 저장, 조직, 검색 관리메타데이터 관리 포함디렉토리파일들의 논리적 컨테이너계층적 구조 (트리 구조)파일 검색, 그룹화 용이파일과 디스크파일 할당 방식: 연속, 연결, 인덱스 할당빈 공간 관리디스크 스케줄링 알고리즘 자료구조와 알고리즘정렬 - 삽입정렬원리: 정렬된 부분에 새 원소를 적절한 위치에 삽입시간 복잡도: 평균 및 최악 O(n^2), 최선 O(n)특징: 작은 데이터셋에 효율적, 부분 정렬된 배열에 유리안정적 정렬 알고리즘정렬 - 병합정렬원리: 분할 정복 방식, 작은 부분으로 나누고 병합하며 정렬시간 복잡도: 항상 O(n log n)특징: 대규모 데이터 정렬에 효율적, 추가 메모리 필요안정적 정렬 알고리즘정렬 - 퀵정렬원리: 피벗 선택 후 분할 정복 방식으로 정렬시간 복잡도: 평균 O(n log n), 최악 O(n^2)특징: 실제 구현에서 매우 빠름, 불안정 정렬피벗 선택 방법이 성능에 큰 영향동적 프로그래밍 - 메모이제이션원리: 계산 결과를 저장하고 재사용 (캐싱)특징: 주로 하향식(top-down) 접근법장점: 중복 계산 방지로 효율성 향상적용: 피보나치 수열, 최장 공통 부분 수열 등동적 프로그래밍 - 타뷸레이션원리: 작은 부분 문제부터 해결하며 표를 채움특징: 상향식(bottom-up) 접근법장점: 일반적으로 메모리 사용량이 적음적용: 냅색 문제, 최단 경로 문제 등3주차 후기지난 주차보다는 익숙한 단어들이 많이 보였다. 그래서 조금 가벼운 마음으로 시작했다가 어김없이 혼돈으로 접어드는 루트의 반복이었던 주였다. 언제쯤 이 단어와 개념과 친구 먹을 수 있을까 😂운영체제에서는 가상 메모리에 대해 배우면서 세그멘테이션과 페이징의 개념을 잡고, 메모리 관리 기법의 발전 과정을 따라 공부해 보았다. 입출력 장치와 파일 시스템에 대해 공부하면서는 하드웨어와 소프트웨어의 상호작용을 중점으로 공부했는데, SSD와 하드디스크에 대한 내용을 공부할 때는 노트북 살 때의 경험을 떠올리면서 들으니 다른 파트보다 조금 더 재밌게 들을 수 있었던 것 같다.알고리즘에서는 다양한 정렬 방법들과 동적 프로그래밍에 대해 배웠다. 정렬에 대해 공부할 때는 각각의 장단점을 비교하면서 언제 적합하게 사용할 수 있을지를 주요 포인트로 공부했다. 이미 이전에도 몇 번 봤던 개념이라 막 어렵다는 느낌은 없었다. 그런데 동적 프로그래밍이 개인적으로 좀 어려웠던 것 같다. 동적인건 언제나 어렵다, 다 정적이었으면 좋겠다 라고 궁시렁 거리면서 공부했다. 그래도 감자쌤과 함께 찬찬히 공부하니 완벽하게는 아니어도 어렴풋이 개념은 잡을 수 있었던 것 같다. 인프런 워밍업 클럽 2기 후기한 번도 공부해보지 않은 CS를 공부해보겠다고 시작한 워밍업 클럽은 생각보다 빠르게 지나갔다. 회사 일이랑 이직 준비랑 다른 스터디에 엄청 치이면서도 워밍업 클럽을 포기하지 않은 건, 하루에 수행할 수 있는 적합한 학습량과 감자쌤의 친절나긋한 설명 덕분이 아닐까 싶다. 그리고 워밍업 클럽을 같이 진행하면서 열심히 하시는 다른 분들의 모습에도 많은 자극을 받았던 것 같다. 3주 동안 감자쌤과 함께 배운 내용들을 완벽하게 이해했다고 할 수는 없지만, 전반적인 내용을 파악했고 어느 부분이 어려운지도 알았으니 앞으로 공부하면서 부족한 부분들을 더 채워나가야겠다.

알고리즘 · 자료구조인프런인프런워밍업클립CS운영체제자료구조알고리즘감자3주차

서채영

[인프런 워밍업클럽 CS 2기] 마지막 주 미션

운영체제1. 메모리의 종류는 어떤것들이 있나요? 각 메모리의 특징도 함께 적어주세요.레지스터: 휘발성 메모리, CPU 내부 메모리로 ALU의 계산을 위한 값들을 저장하는 용도. 캐시 메모리: 휘발성 메모리, 레지스터와 RAM사이의 병목 현상을 줄이기 위한 메모리RAM: 휘발성 메모리, 프로그램을 실행 시, 해당 메모리에 올라가서 프로세스가 됩니다.보조저장장치: 비휘발성 메모리, HDD, SSD, 파일 저장 공간 2. 사용자 프로세스가 메모리의 운영체제 영역에 침범하지 못하도록 만든 레지스터는 어떤 레지스터일까요?경계 레지스터입니다.  3. 메모리 할당 방식에서 가변 분할 방식과 고정 분할 방식의 장단점은 뭔가요?[가변 분할 방식]장점: 공유와 각 영역에 대한 메모리 접근 보호가 편리하고, 영역 별로 분할되기 때문에 관리가 쉽습니다.단점: 외부 단편화가 발생합니다.[고정 분할 방식]장점: 외부 단편화를 해결하고, 효율적인 메모리 관리가 가능합니다.단점: 내부 단편화와 특정 영역에 대한 공유, 권한 부여가 어렵습니다. 4. CPU 사용률을 올리기 위해 멀티프로그래밍을 올렸지만 스왑이 더 많이 이루어져 CPU 사용률이 0%에 가까워 지는 것을 뭐라고 할까요?스레싱입니다. 제한된 물리 메모리에 의해 스왑 영역에 데이터가 많이 저장되고 Page Fault가 많이 발생하게 되면 스왑을 하는데 이 작업에 의한 오버헤드로 CPU 사용률이 떨어지며, 이를 통해 CPU 스케줄러에 의해 CPU 사용률을 올리기 위해 메모리에 더 많은 프로세스를 올리며 CPU 사용률이 0%에 가깝게 떨어지게 된다. 5. HDD나 SSD는 컴퓨터를 실행시키는데 꼭 필요한 걸까요?이유를 함께 적어주세요.메모리에서 비휘발성의 특성을 가진 메모리는 HDD나 SSD 밖에 없어서 운영체제를 저장할 공간이 필요하기 때문입니다.  6. 파일을 삭제해도 포렌식으로 파일을 복구할 수 있는 이유가 무엇일까요?빈 공간을 모아둔 free block list를 가지고 있기때문에 삭제 시 파일 정보를 모두 지우는 게 아니라 파일 테이블의 헤더를 삭제하고 free block list에 추가합니다. 자료구조와 알고리즘1. 지금까지 배운 5개의 정렬 알고리즘의 장단점과 시간 복잡도를 적어주세요.버블 정렬 : O(n²)선택 정렬 : O(n²)삽입 정렬 : O(n²)병합 정렬 : O(nlogn)퀵 정렬 : 평균 O(nlogn) / 최악 O(n²) 2. 메모리가 부족한 시스템에서 어떤 문제를 해결하는데 재귀로 쉽게 구현이 가능할 것 같습니다.여러분이라면 메모이제이션과 타뷸레이션 중 어떤 걸 이용하실 건가요? 이유를 함께 적어주세요.타뷸레이션을 사용하겠습니다. 반복문을 사용해서 순차적으로 계산하기 때문에 오버헤드가 적고 빠른 동작이 가능하기 때문입니다.

채널톡 아이콘