새로운 내용을 공부할 때
새로운 내용의 공부를 시작할 때 용어의 정의를 이해하지 못하거나 정확하게 알지 못한다면 그 용어가 포함된 문장을 이해하지 못합니다.
작은 단어 하나가 내용을 이해하지 못하게 하기 때문에 용어를 정확하게 이해하는 것이 중요합니다.
빌드툴과 G1GC,ZGC 학습
오늘 학습
- Gradle과 Maven 비교하기
- G1GC
- ZGC
Gradle과 Maven
Gradle과 Maven은 빌드를 도와주는 도구 입니다.
자바로 개발을 하면서 빌드가 무엇이고, 빌드툴이 왜 필요한지 생각하지 않고 사용을 했습니다.
인텔리제이에서 프로젝트를 만들때 사용할 라이브러리나 프레임 워크를 선택하면 자동으로 추가해줍니다.
빌드
처음 개발을 배울때 Maven Repository
에 들어가서 oracle driver
,tomcat
을 별도로 jar 파일로 다운받아서 사용한 기억이 납니다.
빌드의 정의
빌드는 개발자가 작성한 소스 코드를 실행 가능한 파일로 변환하는 전체 과정을 의미합니다. 이 과정중 주요 단계는 세가지로 분류됩니다.
- 컴파일
소스 코드(.java 파일)를 자바 인 경우 바이트 코드(.class
) 로 변환합니다. 자바 컴파일러(javac
)를 통해 이루어집니다. 코드의 구문 및 의미를 검토하며 오류 검사가 포함됩니다. - 종속성 관리(
Dependency Management
)
필요한 라이브러리나 프레임워크를 프로젝트에 포함시키는 단계입니다. 라이브러리나 프레임 워크를 저장소에 다운받아 직접 관리를 해야합니다. - 패키징:
컴파일된 바이트 코드와 필요한 리소스 파일을 하나의 실행 가능한 파일로 변환합니다. 자바는jar
이나war
로 패키징됩니다.
이 과정 중에 추가하고 싶은 단계가 있을 수 있습니다. 기존 빌드 파일을 삭제하는 클리업 단계, 코드가 올바르게 실행되는지 확인하는 테스트 단계, 테스트 통과후 패키징을 완료하고 배포하거나 다른 작업을 위해 트리거를 하는 단계 등이 있을 수 있습니다.
빌드 도구가 없다면
- 반복적인 작업을 수작업으로 진행해야 하므로 비효율적이며 실수할 수 있음
- 라이브러리를 다운로드 및 추가하는 번거로움
- 개발자들 간의 버전관리 어려움
- 다운받은 jar 파일의 보안 위험
- 현재 프로젝트의 의존성을 파악하기 어려움
빌드 도구를 사용하는 이유
빌드 도구는 연예인 매니저와 같습니다. 필요한 작업, 소품, 목적지 등을 미리 알려주면, 그에 맞게 모든 것을 알아서 진행해줍니다.
빌드 도구마다 정해진 규칙이 있으므로, 그 규칙에 맞게 작업을 요청하는 것이 빌드 도구를 사용하는 방식입니다.
이러한 도구들은 빌드 프로세스를 자동화하고 효율성을 높여주며, 개발자가 더 중요한 로직에 집중할 수 있게 도와줍니다.
키워드
- 자동화: 빌드 단계와 같은 반복적인 작업을 줄여줍니다.
- 종속성 관리: 프로젝트에 필요한 외부 라이브러리와 프레임 워크 버전을 관리하며, 자동으로 다운로드를 해줍니다.
- 일관성: 어떤 개발 환경에서 동일한 빌드 프로세스를 보장하여 일관된 결과를 얻을 수 있습니다.
Maven
Maven은 Ant(빌드 도구)의 한계를 보완하기 위해 등장했습니다.
Ant는 빌드 방식이 절차적 명령어로 작성한 작업 순서대로 동작합니다. 빌드가 복잡할 경우 유지 보수하기 어려웠습니다. 의존성 관리나 자동화도 가능하지만 모두 수동으로 설정해야합니다.
이런 한계를 Maven은 절차적 방식에서 선언적방식으로 라이프 사이클에 기반하여 동작하게 됩니다. 의존성 관리나 수동으로 하는 Ant에 비해, Maven은 중앙 저장소를 통해 자동으로 라이브러리와 프레임워크를 다운로드하며 다양한 플러그인을 제공합니다.
Ant와 Maven 모두 XML로 작성된 방식입니다. 계층 구조로 작성해야하며 프로젝트 의존성이나 빌드 단계가 복잡해질 경우 XML의 필수 구조인 태그로 인해 유지보수와 가독성이 떨어질 수 있습니다.
Maven은 빌드를 시도할 때마다 전체 프로젝트를 다시 빌드하는 방식이기 때문에 속도 저하가 발생합니다. Maven은 점진적 빌드를 지원하지 않아 변경된 부분만 빌드할 수 없기 때문입니다.
그럼에도 불구하고, Maven은 현재도 많이 사용하고 있습니다. Maven을 사용하는 기존 프로젝트를 변형하는 과정에 협업이나 학습이 필요하므로 유지하기 때문이라고 생각합니다. Maven도 역시 표준화된 프로젝트 구조와 라이프사이클 관리로 인해 일관된 빌드 프로세스를 유지할 수 있기 때문입니다.
점진적 빌드(Incrimental Build)
전체 프로젝트를 빌드하지 않고, 변경된 부분만 다시 빌드하는 방법을 말합니다.
- 마지막 빌드 호출 이후 변경된 부분만 빌드
- 변경되지 않은 부분은 캐시 결과로 검색해 재사용
- 태스트의 입력,출력 혹은 변경되지 않은 부분은 빌드하지 않음
키워드
- 설정 기반 방식: 모든 설정을 명시적으로 정의하여 일관성을 유지하지만 유연성은 제한됩니다.
- XML: 계층 구조로 작성되며 재사용하기 어렵습니다.
Gradle
Gradle은 Maven의 XML 구조의 한계를 DSL(Domain Specific Language)로 보완한 빌드 도구입니다.
JVM 기반 언어인 Groovy 또는 Kotlin DSL을 사용하여 빌드 스크립트를 작성함으로써, 더 간결하고 유연하게 빌드 설정이 가능합니다.
주요 특징
- 멀티 모듈 지원
멀티 프로젝트 빌드를 지원하며, 여러 모듈을 하나의 프로젝트로 관리할 수 있습니다. 각 모듈은 독립적으로 빌드되며, 모듈 간의 의존성을 명시적으로 정의할 수 있습니다. 이를 통해 대규모 프로젝트에서도 효율적인 빌드 관리가 가능합니다. - 점진적 빌드와 빌드캐시
- 점진적 빌드: 변경된 파일만 다시 빌드하는 방식을 지원합니다. 이런 방식을 통해 빌드 시간을 단축할 수 있습니다.
- 빌드 캐시: 이전 빌드의 결과를 캐시하여 저장합니다. 동일한 작업이 반복되는 경우 재사용으로 반복저거인 빌드 작업의 효율성을 높여줍니다.
- 설정 주입 방식
Gradle은Groovy
,Kotlin DSL
을 사용하여 빌드 스크립트를 작성합니다. 이는 동적으로 설정을 변경하거나, 복잡한 빌드를 유연하게 작성하게 하여 재사용이나 유지보수가 Maven 방식보다 유리합니다.
Gradle 의존성 사용방법
api: 내부 의존성을 컴파일과 런타임 모두 보이는 API 의존성입니다.
implementation: 내부 의존성을 런타임에서만 보이는 구현 의존성
compileOnly: 컴파일에만 사용되는 의존성 정의
runtimeOnly: 런타임에만 사용되는 의존성 정의
test + { implementation, compileOnly ,runtimeOnly} : 해당 의존성을 테스트 시에만 사용하도록 정의
dependencies {
// 내부 의존성으로 런타임에서만 보이는 구현 의존성
implementation 'org.springframework.boot:spring-boot-starter-web'
// 컴파일에만 사용되는 의존성 정의
compileOnly 'org.projectlombok:lombok:1.18.20'
annotationProcessor 'org.projectlombok:lombok:1.18.20'
// 런타임에만 사용되는 의존성 정의
runtimeOnly 'mysql:mysql-connector-java:8.0.26'
// 테스트 의존성 정의
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testCompileOnly 'org.projectlombok:lombok:1.18.20'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.7.2'
}
의존성 주의사항
이번 주말에 추가할 예정입니다
실제 코드로 작성하여 이렇게 동작하는지 확인합니다.
- 무한 리필 모듈에서는 삼겹살을
api
로 의존합니다. - 커피가게 모듈에서는 커피머신을
implementation
으로 의존합니다
이때 삼겹살 모듈이 수정되는 경우 빌드를 새로하게 되면 무한 리필, 손님까지 리빌드 하게 됩니다.
커피머신 모듈이 수정되는 경우 커피가게만 리빌드하게 됩니다
implementation
모듈 간의의존성 그래프가 줄어들어, 빌드 속도가 향상될 수 있습니다. 변경된 모듈의 의존성만 리컴파일 되므로, 손님은 커피머신의 수정사항을 모르기 때문에 리빌드를 하지 않아도 됩니다.
api
모듈 간의 의존성 전파가 발생합니다. 변경된 모듈의 영향을 받는 다른 모듈도 리컴파일 될 수 있습니다. 삼겹살 모듈이 수정되어 재빌드할경우 손님까지 의존성 전파로 리빌드하는 과정이 발생하게 되는 것을 말합니다.
GC
G1GC
G1GC는 기존 메모리 관리 방식과 다르게 GC 관리 영역이 나누어져있지 않고 고정 크기의 리전을 만들어 사용합니다.
지정한 OLD 비율이 되기전까지는 기존과 동일한 minor gc가 발생하며 old 비율이 지정한 비율만큼 되면 이제 major gc를 준비합니다.
Minor GC:
- 동작 기준: 주기적으로 Young Generation의 메모리가 부족해질 때 발생합니다.
- 작업: Eden 영역에서 살아남은 객체를 Survivor 영역으로 복사하거나 Old 영역으로 승격합니다.
- 목적: Young Generation의 메모리를 회수하고 재사용 가능하게 합니다.
Initial Mark:
- 동작 기준: Old Generation의 사용 비율이 특정 임계값을 초과할 때 Major GC가 시작됩니다.
- 작업: Root Set을 스캔하여 Old Region이 참조하는 객체들을 마킹합니다.
- 특징: STW(Stop-The-World) 상태에서 매우 짧은 시간 동안 수행됩니다.
- 목적: 정확한 마킹을 위해 Young Generation에서 Minor GC가 완료된 후 깔끔한 상태의 Survivor Region을 사용합니다.
Root Region Scan:
- 작업: Initial Mark 단계에서 마킹된 객체들을 기준으로 추가 객체들을 마킹합니다.
- 목적: Survivor Region을 새로운 Root Set으로 사용하여 Old Region의 객체들을 효율적으로 마킹합니다.
Concurrent Mark:
- 작업: 힙 전체를 병렬로 스캔하여 살아있는 객체들을 마킹합니다.
- 특징: 애플리케이션 스레드와 병렬로 수행됩니다.
- 목적: 전체 힙에서 살아있는 객체를 효율적으로 식별합니다.
Remark:
- 작업: Concurrent Marking 동안 놓친 살아있는 객체들을 최종적으로 마킹합니다.
- 특징: STW(Stop-The-World) 상태에서 수행됩니다.
- 목적: 정확한 마킹을 완료하고 unreachable(도달 불가능한) 객체들을 식별합니다.
Cleanup:
- 작업: 살아있는 객체 비율이 낮은 Region을 정리하고, 도달 불가능한 객체를 제거합니다.
- 특징: 일부 작업은 STW 상태에서 수행됩니다.
- 목적: 메모리 단편화를 줄이고, 비워진 Region을 Freelist에 추가하여 재사용 가능하게 합니다.
Copying (Evacuation):
- 작업: 살아남은 객체를 새로운 Region으로 이동하여 메모리를 압축합니다.
- 목적: 메모리 단편화를 줄이고, 사용 가능한 연속된 메모리 공간을 확보합니다.
Mixed GC:
- 동작 기준: Old Generation의 사용 비율이 특정 임계값을 초과할 때 여러 번에 걸쳐 수행됩니다.
- 작업: Young Generation과 Old Generation의 일부를 함께 수집합니다.
- 목적: 메모리 회수를 보다 효율적으로 수행합니다.
- 특징: 비용이 크기 때문에 여러 번에 나누어 수행됩니다.
그림으로 정리하려고 했는데 핸드폰이 너무 작아서 포기..
정리하다보니 이해가 안가는게 있어서 GC는 이후에 다시 정리해보겠습니다.
댓글남기기