2주 차에서 다룰 내용은 다음과 같다.
1. Computer Architecture
- 고정 소수점/ 부동 소수점
- 패리티 비트/ 해밍 코드
- ARM 프로세서
2. Java
- 고유 락
- 문자열 클래스
- Garbage Collection
- Primitive type & Reference type
Computer Architecture
컴퓨터에서 실수를 표현하는 방법은 고정 소수점과 부동 소수점 두 가지 방식이 존재한다.
고정 소수점/ 부동 소수점
고정 소수점(Fixed Point)이란?
소수점이 찍힐 위치를 미리 정해놓고 소수를 표현하는 방식이다. (정수 + 소수)
ex) -6.12345 -> 부호(-)와 정수부(6), 소수부(0.12345) 3가지 요소가 필요함
장점: 실수를 정수부와 표현하여 단순하다.
단점: 표현의 범위가 너무 적어서 활용하기 힘들다.
부동 소수점(Floating Point)이란?
실수를 가수부 + 지수부로 표현한다.
가수: 실수의 실제값 표현
지수: 크기를 표현함. 가수의 어디쯤에 소수점이 있는지 나타낸다. -> 소수점의 위치가 고정 x
장점: 표현할 수 있는 수의 범위가 넓어진다.
단점: 오차가 발생할 수 있다.
패리티 비트/ 해밍 코드
패리티 비트란?
정보 전달 과정에서 오류가 생겼는지 검사하기 위해 추가하는 비트.
전송하고자 하는 데이터의 각 문자에 1비트를 더해서 전송.
패리티 비트는 짝수(짝수 패리티 비트)나 홀수(홀수 패리티 비트) 개가 되도록 한다.
해밍 코드란?
해밍 코드를 사용하는 이유는 패리티 비트는 오류를 검출하기만 하고 수정하지는 않는다. 따라서 해밍 코드를 활용한다.
데이터 전송 시 1비트의 에러를 정정할 수 있는 자기 오류 정정 코드이다.
패리티 비트를 보고, 1비트에 대한 오류를 정정할 곳을 찾아 수정할 수 있다.
2의 n승 번째 자리인 1,2,4번째 자릿수가 패리티 비트라는 것으로부터 시작한다.
이 숫자로부터 시작하는 세 개의 패리티 비트가 짝수인지, 홀수인지 기준으로 판별함.
ex) 짝수 패리티의 해밍 코드가 0011011이다.
1. 1 , 3, 5, 7 번째 비트 확인: 0101로 짝수 : '0'
2. 2, 3, 6, 7번째 비트 확인: 0111로 홀수 :'1'
3. 4, 5, 6, 7번째 비트 확인: 1011로 홀수 '1'
역순으로 패리티 비트는 '110'이 도출한다 10진법으로 바꾸면 6이 된다. 즉 6번째 비트를 수정하면 된다.
0011011 -> 0011001이 된다.
ARM 프로세서
프로세서란 메모리에 저장된 명령어들을 실행하는 유한 상태 오토마톤이다.
오토마톤: 사람이 행하는 어떤 목적에 합당한 약간 복잡한 동작을 기계적인 제어 기구에 의하여 실시하는 장치(자동 기계)
ARM : Advanced RISC Machine
진보된 RISC기기의 약자이다. RISC는 감소된 명령 집합 컴퓨팅의 뜻을 가지고 있다.
단순 명령 집합을 가진 프로세서가 복잡한 명령 집합을 가진 프로세서보다 훨씬 더 효율적일 것이라는 생각으로 탄생하게 되었다.
ARM 프로세서란?
메모리, 인터페이스, 라디오, 시스템 온 모듈 등이 포함된다.
임베디드 기기에 주로 사용되는 32bit 프로세서이다.
RISC 아키텍처가 있는 프로세서는 CISC아키텍처보다 적은 트랜지스터를 필요로 하여 비용, 전력소비 및 열 방출을 향상함.
모바일 기기 또는 Iot 디바이스에 많이 사용된다.
ARM 프로세서 설계 시 고려사항
1. 저전력, 작은 die사이즈로 설계
2. 제한된 메모리를 고려한 코드 직접도
3. 저가격의 메모리 소자 사용
4. 설계 및 제조비용, 주변장치 공간을 위해 임베디드 프로세서가 차지하는 다이 사이즈 줄이기.
JAVA
고유락(Intrinsic Lock)
Java의 모든 객체는 lock을 갖고 있다.
모든 객체가 갖고 있으니 고유락 이라고도 하고, 모니터처럼 작동한다고 하여 모니터 락 혹은 그냥 모니터라고도 한다.
자바의 synchronized 블록은 동시성 문제를 해결하는 가장 간편한 방법으로, 고유 락을 이용하여 여러 스레드의 접근을 제어한다.
public class Counter {
private int count;
public int increase() {
return ++count; // 스레드 안전하지 않은 연산.
}
}
++연산자를 호출했을 때 실제로는 세 가지 연산이 순차적으로 수행된다.
변수 메모리에서 읽고, 증가시키고, 다시 메모리에 쓴다.
두 스레드가 동시에 같은 값을 읽고, 값을 증가시켜 저장하면 increse() 호출 횟수와 count값에 차이가 발생한다.
이는 동시성 프로그래밍에서 문제가 되는 전형적인 read - modify - write패턴이다.
동시성 문제는 결국 여러 스레드가 공유 자원으로 접근하기 때문에 발생한다.
동시성 문제를 해결하기 위해 count 변수로 접근하는 스레드를 제어해야 한다.
public class Counter {
private Object lock = new Object();
private int count;
public int increase() {
synchronized(lock) {
return ++count;
}
}
}
lock이라는 Object인스턴스를 이용하여 여러 스레드가 동시에 count 변수에 접근하지 못하도록 제어했다.
이제 increase() 메서드는 한 번에 한 스레드만 실행할 수 있다. 한 스레드가 먼저 락을 획득한 경우 다른 스레드는 기다려야 한다.
Counter의 인스턴스도 자바 객체이므로 락으로 사용할 수 있다.
public class Counter {
private int count;
public int increase() {
synchronized(this) {
return ++count;
}
}
}
this를 이용하여 별도의 락 생성 없이 synchronized블록을 구현했다. 하지만 더 쉽게 구현할 수 있다.
예제의 synchronized블록은 increase() 메서드 전체를 감싸고 있는데, 이런 경우에는 메서드에 synchronized 키워드를 붙이는 것으로 대신할 수 있다.
public class Counter {
private int count;
public synchronized int increase() {
return ++count;
}
}
재진입 가능성(Reentrancy)
자바의 고유 락은 재진입이 가능하다. 재진입이 가능하다는 것은 락의 획득이 호출 단위가 아닌 스레드 단위로 일어난다는 것이다.
이미 락을 획득한 스레드는 같은 락을 얻기 위해 대기할 필요가 없다. 이미 락을 가지고 있다면 같은 락에 대해 synchronized블록을 만났을 때 대기 없이 통과한다.
public class Reentrancy {
public synchronized void a() {
System.out.println("a");
// b가 synchronized로 선언되어 있지만 a진입시 이미 락을 획득하였으므로,
// b를 호출할 수 있다.
b();
}
public synchronized void b() {
System.out.println("b");
}
public static void main(String[] args) {
new Reentrancy().a();
}
}
만약 자바의 고유 락이 재진입이 가능하지 않다면 위 코드는 a메서드 내부의 b를 호출하는 지점에서 데드락이 발생한다.
교착상태(deadlock): 두 개의 스레드에서 서로가 가지고 있는 락이 해제되기를 기다리는 상태
구조적인 락(structuered lock): 고유 락을 이용한 동기화를 구조적인 락이라고 한다.
synchronized블록 단위로 락의 획득/해제가 일어나므로 구조적이라고 한다.
구조적인 락 A와 B가 있다.
A 획득 -> B획득 -> B해제 -> A해제 = 가능
A 획득 -> B 획득 -> A해제 -> B해제 =불가능
가시성(visibility): 한 스레드가 쓴 값을 다른 스레드가 볼 수도 있고 그렇지 않을 수도 있다.
이를 가시성 문제라고 한다.
최적화를 위해 컴파일러나 CPU에서 발생하는 코드 재배열(Reordering)때문에 이런 문제가 발생할 수도 있고,
멀티 코어 환경에서는 코어의 캐시 값이 메모리에 제때 쓰이지 않아 문제가 발생할 수도 있다.
락을 사용하면 가시성의 문제가 사라진다. 자바에서는 스레드가 락을 획득하는 경우 그 이전에 쓰였던 값들의 가시성을 보장한다.
문자열 클래스
String특징
new 연산을 통해 생성된 인스턴스의 메모리 공간은 변하지 않음
Garbage Collector로 제거되어야 한다.
문자열 연산 시 새로 객체를 만드는 Overhead발생
객체가 불변하므로, MUltithread에서 동기화에 신경을 쓸 필요가 없다.
-> String 클래스 : 문자열 연산이 적고, 조회가 많은 멀티스레드 환경에서 좋음
StringBuffer, StringBuilder특징
공통점
new 연산으로 클래스를 한 번만 만듦
문자열 연산 시 새로 객체를 만들지 않고, 크기를 변경시킴
StringBuffer와 StringBuilder클래스의 메 서스가 동일하다.
차이점
StringBuffer는 Thread-Safe 함 / StringBuilder는 Thread-safe하지 않음 (불가능)
StringBuffer 클래스 : 문자열 연산이 많은 Multi-Thread 환경
StringBuilder 클래스 : 문자열 연산이 많은 Single-Thread 또는 Thread 신경 안 쓰는 환경
Garbage Collection
C/C++ 언어와 달리 자바는 개발자가 명시적으로 객체를 해제할 필요가 없다.
사용하지 않는 객체는 메모리에서 삭제하는 작업을 GC라고 부르면 JVM에서 GC를 수행한다.
일반적으로 다음과 같은 경우에 GC의 대상이 된다.
1. 객체가 NULL인 경우
2. 블록 실행 종료 후, 블록 안에서 생성된 객체
3. 부모 객체가 NULL인 경우, 포함하는 자식 객체
Weak Generational Hypothesis
신규로 생성한 객체의 대부분은 금방 사용하지 않는 상태가 되고, 오래된 객체에서 신규 객체로의 참조는 매우 적게 존재한다는 가설이다.
이 가설에 기반하여 자바는 Young 영역과 Old 영역으로 메모리를 분할하고, 신규로 생성되는 객체는 Young 영역에 보관하고, 오랫동안 살아남은 객체는 Old 영역에 보관합니다.
1. Young영역
새롭게 생성한 객체의 대부분이 여기로 위치한다.
대부분의 객체가 금방 접근 불가능 상태가 되기 때문에 매우 많은 객체가 Young영역에 생성되었다가 사라진다.
이 영역에서 객체가 사라질 때 Minor GC가 발생한다 말한다.
2.Old영역
접근 불가능 상태로 되지 않아 Young 영역에서 살아남은 객체가 여기로 복사된다.
대부분 Young 영역보다 크게 할당하며, 크기가 큰 만큼 Young 영역보다 GC는 적게 발생한다.
이 영역에서 객체가 사라질 때 Major GC(혹은 Full GC)가 발생한다고 말한다.
3.permanent 영역
Method Area라고도 한다.
JVM이 클래스들과 메서드들을 설명하기 위해 필요한 메타데이터들을 포함하고 있다.
JDK8부터는 PermGen은 Metaspace로 교체된다.
Generational Garbage Collection과정
1. 새로운 객체가 들어오면 Eden Space에 할당
2.Eden space에 가득 차게 되면, minor garbage collection이 시작
3. 참조되는 객체들은 첫 번째 survivor(S0)로 이동, 비 참조 객체는 Eden space가 clear 될 때 반환된다.
4. 다음 minor GC때, Eden space에서는 같은 일이 일어난다. 참조되는 객체들은 두 번째 survivor(S1)으로 이동, 비 참조 객체는 clear
5. 다시 같은 과정이 반복되지만, 참조되는 객체들은 (S0)로 이동되고 비 참조 객체들은 전부 clear 된다.
6.minor GC 후 aged 오브젝트들이 일정한 age threshold을 넘게 되면 그들은 young generation에서 old로 promotion 됨
7.minor GC가 계속되고 계속해서 객체들이 Old Generation으로 이동
8.major GC가 old Generation에 시행되고, old Generation은 Clear 되고, 공간이 Compact 된다.
Primitive type & Reference type
자바에는 기본형(Primitive type)과 참조형(Reference type)이 있다.
Primitive type (기본형 타입)
자바는 8가지 기본형을 제공한다.
기본형은 반드시 사용 전 선언되어야 함.
비 객체 타입이다. -> null값을 가질 수 없음
스택 메모리에 저장된다.
Reference type (참조형 타입)
자바에서 기본형을 제외한 타입은 모두 참 조형이다.
참조형은 자바의 최상위 클래스인 Object를 상속받은 클래스이다.
new로 인하여 생성하는 것들은 메모리 영역인 Heap 영역에 생성을 하게 되고,
Garbage Collector가 돌면서 메모리를 해제한다.
빈 객체를 의미하는 Null이 존재한다.
Heap 메모리에 생성된 인스턴스는 메서드나 각종 인터페이스에서 접근하기 위해 JVM의 Stack 영역에 존재하는 Frame에 일종의 포인터인 참조값을 가지고 있어 이를 통해 인스턴스를 핸들링한다.
'CS' 카테고리의 다른 글
HTTP 상태 코드 (2) | 2023.01.04 |
---|---|
5주차 CS 스터디 Operating System&Spring (1) | 2022.11.08 |
4주차CS스터디Network&Spring (0) | 2022.10.27 |
3주차CS스터디Network&Java (0) | 2022.10.14 |
1주차 CS스터디 Computer Architecture & Java (8) | 2022.09.21 |