본문 바로가기

분류 전체보기116

애노테이션 프로세서 애노테이션 프로세서 일반적으로 애노테이션에 대한 코드를 검사, 수정 또는 생성하는데 사용된다. 본질적으로 애노테이션 프로세서는 java 컴파일러의 플러그인의 일종이다. 애노테이션 프로세서를 적재적소에 잘 사용한다면 개발자의 코드를 단순화할 수 있다. 애노테이션 프로세스의 대표적인 예로 Lombok이 있다. Lombok은 @Getter, @Setter, @Builder 등의 애노테이션과 애노테이션 프로세서를 제공하여 표준적으로 작성해야할 코드를 개발자 대신 생성해주는 라이브러리이다. Lombok(롬복)은 어떻게 동작하는 걸까? @Getter @EqualsAndHashCode @RequiredArgsConstructor public class Member { private final String name; .. 2023. 8. 18.
Proxy 패턴과 JDK Dynamic Proxy, CGLIB Proxy 패턴 특정 객체에 대한 접근을 제어하거나 기능을 추가할 수 있는 패턴이다. 즉, 클라이언트가 사용하려고 하는 대상을 실제 대상인 것처럼 위장해서 클라이언트의 요청을 받는다. 프록시 패턴의 장점에는 초기화 지연, 접근 제어, 로깅, 캐싱 등 다양하게 응용해 사용할 수 있다는 것이다. Proxy 패턴 구성 요소 위 그림은 인터페이스와 인터페이스 구현체를 사용하는 구조를 설명하는 그림이다(위 그림과 다르게 인터페이스가 아닌 클래스 상속을 사용할 수도 있다). 인터페이스 기반의 Proxy 패턴은 특징으로는 본인의 타입을 참조하는 필드를 하나 가지고 있다. 이 필드를 가지고 있는 이유는 RealSubject를 참조하기 위함이다. 해당 필드의 operation() 메서드는 RealSubject의 메서드를.. 2023. 8. 17.
Reflection과 Annotation을 이해하고 DI 컨테이너 만들기 Reflection JVM은 클래스 정보를 클래스 로더를 통해 읽어와서 해당 정보를 JVM 메모리에 저장한다. 그렇게 저장된 클래스에 대한 정보가 마치 거울에 투영된 모습과 닮아있어, 리플렉션이라는 이름을 가지게 되었다. 리플렉션을 사용하면 생성자, 메서드, 필드 등 클래스에 대한 정보를 아주 자세히 알아낼 수 있다. 리플렉션을 사용한 애노테이션은 여러 라이브러리, 프레임워크에서 많이 사용된다. 스프링에서는 의존성 주입, MVC 뷰에서 넘어온 데이터를 객체에 바인할 때, 하이버네이트에서는 @Entity 클래스에 Setter가 없다면 리플렉션을 사용한다. 그리고 클래스 로더에 대한 개념에 대해 어느정도 이해할 필요가 있어 아래 블로그 글을 정리하였다. JVM 메모리 구조 JVM 성능에 관심이 있다면 기본적.. 2023. 8. 13.
try-finally 보다는 try-with-resources를 사용하자 try-finally Java를 처음 배울때 finally 블록은 예외가 발생하든 발생하지않든 항상 실행이 되기 때문에 finally 블록에서 자원을 반납하라고 배웠다. 하지만 Java 8 이상부터는 try-finally는 더이상 최선의 방법이 아니다. try-with-resources를 써야한다. try-finally 예시코드 public class Copy { private static final int BUFFER_SIZE = 8 * 1024; static void copy(String src, String dst) throws IOException { FileInputStream in = new FileInputStream(src); try { FileOutputStream out = new Fi.. 2023. 8. 10.
Finalizer와 Cleaner가 아닌 AutoCloseable을 사용하자 finalizer와 cleaner는 기본적으로 자원을 반납할 때 사용하는데 둘 모두 우리가 원하는 순간에 실행된다는 보장이 없다. 자원을 반납해야 하는 이유 OS마다 open할 수 있는 개수가 제한이 되어있다. 파일을 open할 때마다 파일 핸들러라는 것이 만들어지는데 쉽게 생각하면 id라고 보면 된다. 이렇게 파일을 너무 많이 open하면 리눅스 기준 "Too many open files" 에러가 발생하게 된다. 이러한 에러가 발생하는 이유 중 하나로 InputStream, OutputStream 같은 자원을 제대로 반납하지 않는 경우 즉, 열려있는 커넥션을 제대로 정리해주지 않기 때문에 발생한다. 따라서 자원을 잘반납하라고 만든 것이 finalizer와 cleaner이지만 의도와 다르게 제목처럼 사용.. 2023. 8. 10.
JVM 메모리 구조 JVM 성능에 관심이 있다면 기본적인 JVM 기술 스택의 구조를 이해해야 할 필요가 있다. JVM 기술을 이해하면 더 좋은 소프트웨어를 개발할 수 있고 성능 이슈를 탐구할 때 필요한 이론적 배경지식을 갖추게 된다. 따라서 JVM이 나오게 된 배경부터 자바 코드를 실행하는 방법에 대해서 알아보자. JVM이 나온 배경 JVM 이전 C/C++ 문제점 위 그림처럼 리눅스에서 컴파일해서 나온 실행파일을 윈도우에서 돌리게 되면 안돌아간다. C/C++는 컴파일 플랫폼과 타겟 플랫폼(= 운영체제 + CPU 아키텍쳐)이 다를 경우, 프로그램이 동작하지 않는다는 문제가 있었다. 이를 해결하기 위해서 크로스 컴파일이라고 하는 것이 나왔다. 이 '크로스 컴파일'은 타겟 플랫폼에 맞춰 컴파일하는 것을 말한다. 이 덕분에 리눅스.. 2023. 8. 9.
LRU 알고리즘 이용한 메모리 직접 관리하는 In-memory 캐시 LRU 알고리즘 LRU 알고리즘은 페이지 교체 알고리즘 중 하나로 사용되는 가장 오랫동안 참조되지 않은 페이지를 교체하는 기법을 말한다. 캐시가 사용하는 리소스의 양은 제한되어 있고, 캐시는 제한된 리소스 내에서 데이터를 빠르게 저장하고 접근할 수 있어야 한다. 이러한 LRU 알고리즘은 다음과 같은 특징을 갖는다. 장점 빠른 액세스: 가장 최근에 사용한 요소부터 가장 적게 사용한 요소까지 정렬된다. 따라서 요소에 접근할 경우, O(n)의 시간 복잡도를 가진다. 빠른 Update: 하나의 요소에 액세스할 때마다 업데이트되며, O(n)의 시간 복잡도를 가진다. 단점 많은 공간을 차지한다. N개의 요소를 저장하는 LRU는 N의 크기를 가지는 1개의 LinkedList(Queue)와 이를 추적하기 위한 N의 크.. 2023. 8. 6.
메모리 정리하는 방법(null, Weak/SoftReference, Background Thread, 메모리 직접 관리) 메모리 누수는 겉으로 잘 드러나지 않아 시스템에 수년간 잠복하는 사례도 있다. 이런 누수는 철저한 코드 리뷰나 힙 프로파일러 같은 디버깅 도구를 동원해야만 발견되기도 한다. 그래서 이런 종류의 문제는 예방법을 익혀두는 것이 매우 중요하다. 메모리 누수가 발생할 수 있는 대표적인 상황 3가지 Stack -> Array Cache -> Map Listener -> List 위 3가지 예제 모두 공통적으로 필드로 객체를 쌓아두는 공간이 있다. 즉, 자기 메모리를 직접 관리하기 때문에 메모리 누수에 취약한 것이다. 객체를 쌓아두는 공간에 활성 영역에 속한 요소들은 사용되고 비활성 영역은 쓰이지 않는데 문제는 가비지 컬렉터가 이 사실을 알 길이 없다. 가비지 컬렉터가 보기에는 비활성 영역에서 참조하는 객체도 똑같.. 2023. 8. 6.
프로세스 관리 프로세스 생성의 목적 리눅스에서는 두 가지 목적으로 프로세스를 생성한다. 목적 1: 같은 프로그램의 처리를 여러 개의 프로세스가 나눠서 처리한다. 예를 들어, 웹 서버처럼 요청이 여러 개 들어왔을 때 동시에 처리해야 하는 경우 목적 2: 전혀 다른 프로그램을 생성한다. 예를 들어, bash로부터 각종 프로그램을 새로 생성하는 경우 위의 생성 목적에 fork()와 execve() 함수를 사용한다(시스템 내부에서는 clone()과 execve() 시스템 콜을 호출한다.) fork() 함수 위 목적1에는 fork() 함수만을 사용한다. fork() 함수를 실행하면 실행한 프로세스와 함께 새로운 프로세스가 1개 생성된다. 생성 전의 프로세스를 부모 프로세스(parent process), 새롭게 생성된 프로세스를.. 2023. 8. 4.