회고

스프링 스터디 2주차에 공부한 것들

728x90
  • 힙덤프
    • OOM는 메모리 누수 상황이 발생했을 때 일어남
    • OOM의 종류
      • Java heap space : 힙 공간에 새로운 객체를 생성할 수 없는 경우. 지정한 힙크기가 애플리케이션에 충분하지 않을 경우 발생. 혹은 생명주기가 긴 애플리케이션의 경우. 혹은 finalize를 과도하게 사용하는 애플리에키션에서 발생하기도 함.
      • GC Overhead limit exceede : GC에서 자바 프로그램이 느려지는 경우 발생함.  GC후 자바 프로세스가 컬렉션 수행하는데 걸리는 시간의 약 98% 이상을 소비하고 힙의 2% 미만이 복구된 상태에서 지금가지 수행하는 과정에서 GC중 OOM이 5번 이상 생성되는 경우 발생.
        • 힙의 크기를 늘리면 해결됨. -XX:-UseGCOverheadLimit 선택사항을 추가하여 GC제한 명령을 해제할 수 있음
      • Requested array size exceeds VM limit : 요청 배열 크기가 VM 제한을 초과
        • 원인 : 애플리케이션이 힙 공간보다 큰 배열을 할당할 때 발생. 
        • 힙 사이즈가 너무 작거나, 배열 요소를 계산하고 더하는 등의 배열의 크기가 계속해서 늘어나는 경우 발생
      • MetaSpace
        • 자바 메타데이터(VM에서 자바 클래스)는 원시메모리(메타공간)에 할당된다. 클래스 메타 데이터가 할당될 메타공간이 모두 소모되면 해당 예외 발생함
        • 해결 : MaxMetaSpaceSize 값을 늘려 설정한다. 자바힙과 동일한 주소 공간에 할당된다. 자바 힙의 크기를 줄이면 더 많은 공간을 확보할 수 있다. 자바 힙 공간에 여유가 있는 경우 고려 가능
      • Out of swap space
        • HotSpot VM코드가 네이티브 힙이 고갈되어 네이티브 힙에 할당할 수 없을 경우 발생함. 이 메세지는 실패한 요청의 바이트 크기와 메모리 요청의 이류를 나타낸다. 대개의 경우 할당에 실패한 소스 모듈의 이름을 출력
        • 해결방법 :  네이티브 힙 고갈의 경우는 힙 메모리 로그 및 메모리 맵 정보를 분석하는 것이 유용하다. 이런 유형은 운영체제의 문제 해결 유틸리티를 사용하여 문제를 진단할 수 있다.
      • Compressed class space(압축된 클래스 공간)
        • 64비트 플랫폼에서 클래스 메타데이터 포인트는 32비트 오프셋으로 표현된다. 이 방식은 기본값 활성화로 제어할 수 있으며 활성화되면 클래스 메타데이터가 사용할 수 있는 공간의 크기가 고정된다.
        • 해결방법 : CompressedClassSpaceSize 크기를 키우거나, UseCompressedClassPointers를 비활성화 시킨다.
      • stack_trace_with_native_method
        • 원시 세머드에서부터 스택 트레이스가 출력되었다는 것을 의미하고, 네이티브 메서드에 할당 오류가 발생했음을 의미한다. 이 메세지가 이전 메세지들과 다른 점은 JVM코드가 아니라 Java Native Interface또는 원시 인터페이스에서 할당실패가 감지되었다는 것이다.
        • 이 예외가 발생했다면 운영체제가 제공하는 유틸리티를 이용해서 문제점을 진단해야 한다.
    • 힙덤프 분석 방법
      • 주의점 : 힙 히스토그램을 생성하려면 어플리케이션에 부하가 발생하여 실제 프로덕션에서 절대 실행하면 안됨. 
      • 명령어 기반
        • jmap
          • $ jmap -histo [processId] : 죽은 객체까지 포함함. (GC동반하지 않음)
          • $ jmap -histo:live [processId] : 풀 GC 발생.
        • jcmd
          • $ jcmd [processId] GC.class_histogram
            • 풀 GC를 발생시켜 살아있는 인스턴스의 점유율만 보여줌
        • JMX (Java Management eXtension) : 응용프로그램 및 서비스 를 감시관리하기 위한 도구를 제공하는 자바 API
      • GUI 기반 
        • MAT(Memory Analyze Tool) : 이클립스 기반 힙덤프 파일을 열어볼 수 있는 도구.
        • VisualVM : 오라클 기반 JDK에 포함된 버전, 깃헙에서 제공하는 버전 2가지 존재.
        • Java Mission Control : 오라클에서 제공되는 Java Advanced 제품의 일부. 엔터프라이즈 자바어플리케이션의 상태를 실시간으로 모니터링 할 수 있는 툴. 메모리 탭에서 GC갯수를 볼 수 있다.

 

 

 

  • 스레드덤프
    • JVM에서 현재 활성 상태인 모든 자바 스에드 목록. 스레드의 상태를 정확히 알 수 있음
    • 스레드의 상태 : State라는 이름을 가진 Enum타입을 선언됨.
      • NEW : 스레드가 생성되었지만 아직 실행되지 않은 상태
      • RUNNABLE : 현재 CPU가 점유하고 있는 작업을 수행중인 상태, 자원 분배로 인해 WAITING 상태가 될 수 있다.
      • BLOCKED : Monitor를 획득하기 위해 다른 스레드가 락을 해제하기를 기다리는 상태
      • WAITING : sleep(), wait(), join(), park() 메서드를 이용해 대기하고 있는 상태
      • TIMEWAITING : 차이점은 메서드의 인수로 최대 대기 시간을 명시할 수 있어 외부적인 변화 뿐만 아니라 시간에 의해서 WAITING상태가 해제될 수 있음
      • TERMINATED : 스레드가 실행을 마친 상태.
        • *모니터 : 멀티스레드에서 공유데이터의 동시접근을 막기 위해 컨트롤 하는 메커니즘. 모든 객체는 monitor를 가지고 있음
        • wait : 다른 스레드가 객체에 대한 notify, notifyAll을 호출하기 전까지 대기하는 단계.
        • join : 해당 스레드가 종료되기 전까지 기다림.
    • 스레드간의 경합(공유자원에 대해서 여러 스레드가 동시에 요구를 할 때 일어나는 현상)과 데드락의 원인을 분석하기 위해서 주로 사용.
    • 스레드 덤프 분석 방법
      • jstack을 이용하는 방법
        • $ jstack {pid}
      • jcmd이용
        • $ jcmd MyProgram help Thread.print
      • Java VisualVM을 이용하는 방법
      • kill -3 을 이용하는 방법(리눅스)
        • ps -ef | grep java를 통해 pid를 구한다.
        • kill -3 {pid} 을 통해 구할 수 있음
      • MBean 이용하기
    • 스레드 덤프의 패턴
      • 락을 획득하지 못한 경우(BLOCKED)
        • 한스레드가 락을 소유하고 있어 다른 스레드가 락을 획득하지 못해 애플리케이션의 전체적인 성능이 느려지는 경우
      • 데드락 상태 (서로의 락을 얻으려고 하는상태
        • 스레드 A가 작업을 계속하려면 B의 락을 획득해야하고, B가 작업을 계속하려면 A가 소유한 락을 획득해야 하는 상황
      • 원격 서버로부터 메세지 수신을 받기 위해 계속 대기하는 경우
        • RUNNABLE 상태에서 문제가 없어 보이지만, socketReadThread가 계속 소켓을 읽으려 무한정 대기하고 있는 상태
      • WAIT 상태에 있는 경우
      • 스레드 리소스를 정상적으로 정리하지 못하는 경우
        • 불필요한 스레드가 계속해서 늘어나는 경우. 스레드 리소스를 정상적으로 정리 못하고 있는 경우여서 각 스레드를 정리하는 모습 혹은 스레드가 종료되는 조건을 확인하는 것이 좋다.
    • 스레드 덤프를 이용한 문제 해결 예제
      • CPU 사용률이 높을 때 : CPU를 가장 많이 점유하는 스레드가 무엇인지 추출
      • 수행 성능이 비정상적으로 느릴 때 : BLOCKED 상태인 스레드가 원인인 경우가 많음.
        • DBMS에서 주로 나타나는데, DBCP 등의 설정이 적절하지 못해 충분한 성능을 내지 못하는경우, 이 경우 스레드 덤프를 여러번 얻어서 비교하면 BLOCKED 상태에 있던 스레드 중 몇 개는 다른 상태인 경우가 많을 걸이다.
        • DBMS와의 연결이 비정상적인 상태라 계속 타임아웃 시간까지 대기하는 경우. 이 경우에는 스레드 덤프를 여러번 추출해 비교해도 DBMS와 관련된 스레드는 계속해서 BLOCKED 상태에 있다. 타임아웃 값을 적적하게 변경해서 문제 발생 시간을 줄일 수 있음.
    • 스레드 덤프의 정보
      • 스레드 이름 : 스레드의 고유 이름. Thread 클래스를 이용해 스레드를 생성하면 Thread-N 형식으로 스레드 이름이 생성됨
        • ThreadFactory 클래스를 이용했으면 pool-N-thread-N 형식으로 생성됨
      • 우선순위 : 스레드의 우선순위
      • 스레드 ID : 해당정보를 이용해 스레드의CPU사용,메모리 사용등 확인가능
        • 16진수임
        • tid : 자바레벨 스레드 id,
        • nid : 네이티브 스레드 id, OS 영역이고 유니크함. ps 명령어를 이용해 cpu 사용율 알 수 있음
      • 스레드 상태
        • runnable
        • blocked
          • deadlock의 심 가능
        • wait 
      • 콜스택 : 스레드의 콜스택 정보
  • 코어 덤프
    •  특정 시점에 작업중이던 메모리 상태를 기록한 것.
    • JVM이 문제가 생기면 hs_err_pid.log라는 파일을 남기고 죽음. 

 

  • 스레드풀
    • 스레드를 미리 생성해두고 사용자의 요청을 작업큐에 넣고, 작업큐에서 태스크를 미리 생성해놓은 스레드를에게 할당하는것.
    • 사용자로부터 들어온 요청을 작업큐에 넣고 스레드풀은 작업큐에 들어온 Task를 미리 생성해놓은 스레드들에게 할당하고, 다 처리한 스레드
    • 기본적으로 코어의 갯수와 동일한 갯수의 스레드를 생성함.
    • 병목현상이 발생하는 I/O와 데이터베이스 작업이 주로 해당됨
    • (스레드 생성비용 64비트 java8 기준 메모리 1MB 예약할당)
    • 적정 스레드풀 갯수 = CPU수 *(CPU 목표 사용량) * (1 + 대기시간 / 서비스 시간)
    • 종류
      • newFixedThreadPool : 주어진 스레드 갯수만큼 생성. 그 수를 유지함. 일부가 종료되면 다시 생성.
        • ExecutorService executor = Executors.newFixedThreadPool()
      • newCachedThreadPool : 처리할 스레드가 많아지면, 그만큼 스레드를 증가시킴 (최대 : Integer.MAX_VALUE)
      • newSingleThreadExecutor : 스레드를 하나만 생성
      • newScheduledThreadPool : 특정 시간 이후, 또는 주기적 작업 스레드 사용시 활용
    • 사용법
      • Executors로 ExeturosService를 생성하였다면, ExecutorService.submit()를 통해 작업을 추가할 수 있다.
    • SingleThreadExecutor : 스레드가 1개인 Executor.시퀀셜하게 처리함.
    • Future : 예약된 작업에 대한 결과를 알 수 있음.
    • 목적(장점)
      • 매번 발생하는 작업을 병렬처리 하기 위해 스레드를 생성/수거 할때의 오버헤드(어떤 처리를 할 때 드는 간접적인 시간, 메모리 비용)를 줄일 수 있다.
      • 다수의 사용자 요청을 처리하기 위해서
    •   단점
      • 너무 많은 스레드를 풀에 만들어 놓으면 놀고있는 스레드로 인한 메모리가 낭비되는 상황 발생 가능
        • (이에대한 해결책으로 자바에서는 ForkJoinPool을 지원함)
      • 데드락 발생 위험.
    • 단점 개선 : Java7에서 ForkJoinPool를 Work Stealing 알고리즘을 통해 구현하였음. 스레드풀에서 Fork(나눠서)Join(합친다)ThreadPool이 사용됨 (스레드가 노는 시간을 최대한 줄이기 위한 시도)내부적으로 WorkStealing알고리즘 구현
      • Work Stealing Algorithm
        • 병렬처리를 위해 전체 작업 목록을 관리하는 작업큐를 사용하면, 작업큐에 접근하는 것 자체가 경쟁이므로 성능 저하 발생할 수 있다.
        • 따라서 일정한 갯수의 스레드를 유지하면서, 스레드마다 독립적인 작업큐를 관리하여, 하나의 스레드 큐가 비게 되면 다른 스레드에서 task를 훔쳐올 수 있게 한다.
      • 작업을 하나의 큰 작업들로서 제공함
      • 첫 스레드가 작업을 가져와 자신의 로컬 큐에 할당 분할한다.
        • 로컬큐에서는 (양쪽 끝으로 넣었다 뺐다 할 수 있는 구조)으로 구성됨. 각 쓰레드는 한쪽끝에서만 일을함. (스택처럼) 하지만 나머지 한쪽 끝에서는 잡을 스틸하러온 다른 스레드가 접근하게 됨.
      • 두번째 스레드가 가져올 작업이 없다면, 첫 스레드의 큐에 있는 분할된 작업을 훔쳐간다. 나머지 스레드도 반복한다.
      • 100 -> 50 -> 25 -> 25 정도의 작업이 수행됨.
      • 모든 스레드가 일을 종료하는 시간이 비슷해짐.
    •   사용법
      • 생성
        • ExecutorService구현 객체는 Executors 클래스의 다음 두가지 메소드 중 하나를 이용해 간편하게 생성가능
          • 초기 스레드 수 : ExecutorService 객체가 생성될 때 기본적으로 생성되는 스레드 수 
          • 코어 스레드 수 : 스레드가 증가한 수 사용되지 않은 스레드를 스레드 풀에서 제거할 때 최소한으로 유지해야할 수
          • 최대 스레드 수 : 스레드풀에서 관리하는 최대 스레드 수
      • 종료
        • 스레드풀에 속한 스레드는 비데몬 스레드이기 때문에 main() 메소드가 실행이 끝나도 애플리케이션 프로세스는 종료되지 않는다. 따라서 스레드풀을 강제로 종료시켜 스레드를 해제시켜줘야 한다. (메모리 릭 발생 가능)
        • ExecutorService 구현객체에서는 3개의 종료 메소드를 제공함
          • shutDown() : 작업큐에 남아있는 작업까지 모두 마무리 후 종료
          • showdownNow() : 작업 잔량 상관없이 강제 종료. 
          • awaitTermination : timeout 시간안에 처리하면 true리턴, 처리하지 못하면 작업스레드들을 interrupt 시키고 false 리턴
      • ForkJoinPool : 큰 태스크를 작은 태스크로 쪼개고 각기 다른 코어에서 병렬적으로 처리후 결과를 취합하는 방식. 내부적으로 Work Stealing 알고리즘이 구현되어 있음. (Devide and Conquer과 흡사.)
      • 인터페이스 (Devide and Conquer 활용 재귀적으로 테스크를 쪼개고 합치는 방법). 다른스레드와의 작업 부하의 균형을 맞춤.
        • ForkJoinPool는 두가지 방법 제공
          • RecursiveAction 클래스
            • 반환값이 없는 작업을 구현할 때 사용함
          • RecursiveTask 클래스
            • 반환값이 있는 작업을 구현할 때 사용함
          • 공통점
            • compute()라는 추상 메소드 제공. 
              • task를 분할하는 로직, 더이상 분할할 수 없을 때 subtask의 결과를 생산하는 로직 두개로 나뉜다
            • compute()로 재귀적으로 작업을 나누고 fork()로 작업큐에 넣는 작업이 계속 반복된다.
            • fork() : 해당 작업을 스레드 풀의 작업 큐에 넣는다. 비동기적으로 실행됨.
            • join() : 해당 작업의 수행이 끝날 때 까지 기다렸다가, 수행이 끝나면 그 결과를 반환함. 동기 메서드

 

 

 

  • 서블릿이란
    • 클라이언트의 요청을 처리하고 그 결과를 동적으로 생성하여 클라이언트에게 전송하는 자바 프로그램
    • CGI(Common Gateway Interface) : 웹서버와 프로그램 사이에 데이터를 주고 받는 규칙
      • 역사 : 1990년 초기 정적인 데이터를 전달하는 것만으로도 충분
      • 웹이 발달하여 입력을 받아 처리하고, 그 결과를 화면에 보여주는 동적인 페이지가 필요하게 됨.
    • Java Servlet
      • 프로세스 단위로 실행되던 것을 부하를 줄이기 위해 더 작은 단위인 스레드로 부하를 줄이기 위해 탄생
      • 톰캣이 이해할 수 있는 순수 자바 코드로만 이뤄진 웹서버용 클래스. 이를 통해 CGI 프로그래밍 가능.
      • 스레드 단위로 실행되어 서버의 부하를 줄이고 추상화 시켜줌
      • 하지만 자바를 사용해서 동적으로 String으로 HTML태그를 생성해야 하는 불편함이 있었음
    • JSP Java Server Page
      • HTML표준에 따라 작성되므로 웹페이지 작성이 편리해짐. 서비스가 요청되면, JSP의 실행을 요구하고 웹서버의 톰캣의 서블릿 컨테이너에서 서블릿 원시코드로 변환.
    • 서블릿 컨테이너 : 서블릿의 생명주기를 고나리하고 요청에 따른 스레드를 생성해준다.
      • 통신 지원 : 서블릿과 웹서버가 통신할 수 있는 손쉬운 방법을 제공함. 소켓을 만들고 특정 포트를 리스닝 하고 연결 요청이 들어오면 스트림을 생성해서 요청을 받는다. 
      • 생명주기 관리 : 서블릿 컨테이너가 기동되는 순간 서블릿 클래스를 로딩해서 인스턴스화 하고 초기화 메서드를 호출하고 요청이 들어오면 적절할 서블릿 메소드를 찾아서 호출함.
      • 멀티스레딩 관리 : 서블릿 컨테이어는 요청이 들어오면 멀티스레딩 환경에서 동시적으로 ㅈ가업을 관리한다.
      • 톰캣이 이에 해당함.
        • 웹서버와 연동하여 실행할 수 있는 자바 환경을 제공하여, JSP와 서블릿을 실행할 수 있는 환경을 제공함. 
        • HTTP 서버 자체도 내장하기도 함.
    • 서블릿의 생명주기
      • init -> service -> doXXX -> destory -> 서블릿 종료
        • 서블릿 클래스 객체가 실행되면 init이 실행되고 클라이언트 요청이 들어올 때 마다 서비스 메소드가 실행되어 요청에 맞는 메소드가 실행된다.
        • 서버가 종료되거나 서블릿이 필요ㅇ벗어져 객체를 메모리에서 제거할 때, 메소드 destory()가 실행됨.
        •  
  • MVC패턴
    • 모델 1
      • 뷰와 로직을 모두 JSP 페이지 하나에서 처리하는 구조
      • 장점 : 구조 단순하고 쉬움
      • 단점 : 출력을 위한 뷰로직과 비지니스 로직을 위한 코드가 섞여 유지보수가 어렵고 코드가 복잡해짐
    • 모델 2
      • JSP페이지와 서블릿(컨트롤러), 로직(모델)을 위한 클래스가 나뉘어 브라우저 요청을 처리함
      • 서블릿은 브라우저 요청에 맞게 그 결과를보여줄 JSP 페이지로 포워딩 함.
      • 포워딩을 통해 컨텍스트를 받은 JSP페이지 결과를 화면을 클라이언트에 전송한다.
      • 모든 요청을 단일 진입점. 하나의 서블릿에서 처리함.
      • MVC
        • 모델 : 비지니스 로직을 담당. 컨트롤러에 의해 로직 처리 요청이 들어오면 수행하고 결과를 반환한다.
        • 뷰: 클라이언트에 출력되는 화면
        • 컨트롤러 : 어플리케이션의 모든 흐름 제어를 맡고 사용자의 처리 요청은 컨트롤러에 집중됨.
      • 커맨드 패턴 : 하나의 명령어를 하나의 클래스에서 처리하도록 구현하는 패턴.
        • 실행된 기능을 캡슐화 하여 주어진 여러 기능을 실행할 수 있는 재사용성이 높은 클래스를 설계하는 패턴.
  • JDBC
    • 자바에서 데이터베이스에 상관없이 DBMS에 접근하기 위해 사용되는 API
    • 인터페이스와 드라이버로 나눠짐.
    • 커넥션 풀
      • JSP 페이지를 실행할 때 마다 커넥션을 생성하고 닫는데 오버헤드가 있어 동시접속자가 많으면 전체 성능이 낮아질 수 있음.
  • JSP필터란?
    • 클라이언트가 서버로 요청할 때 서블릿으로 전달되기 전, 후에 필터링 하기 위한 기술
    • 사용 예
      • 로그인 여부나 권한 검사
      • 캐싱필터
      • 로그기록
      • 데이터압축, 변환
      • 인코딩 처리
      • 공통기능 수행

 

*동시성 : 멀티 태스킹을 위해 싱글코어에서 멀티 스레드가 번갈아가며 실행하는 성질. 스레드가 코어보다 많은 경우. 동시에 실행되는 것 같이 보이는 것. 싱글코어와 멀티코어 모두에서 가능함. 논리적 개념

*병렬성 : 프로세스를 각각 수행함. 프로세서 하나에 코어 여러개가 달림 . 멀티 태스킹을 위해 멀티코어에서 개별 스레드를 동시에 실행하는 성질. 실제로 동시에 여러 작업을 처리하는 것. 멀티코어에서만 가능함. 물리적 개념

코어수 기준으로 보면 됨.

*멀티코어 프로그래밍  : 하나의 작업을 위해 여러개의 CPU 코어를 사용하기 위해 코드를 작성하는 작업

멀티프로세스 프로그래밍 : 여러 CPU코어를 사용하기 위해 코드를 작성하는 작업. fork를 통해 프로세스를 복사한다.

멀티 스레드 프로그래밍. 하나의 프로세스에서 여러개의 스레드를 생성하여 여러 CPU 코어를 사용하기 위해 코드를 작성하는 방법.

하이퍼스레딩 : 하나의 코어를 논리적으로 두개 이상의 코어처럼 동작하도록 설계한 기술

 

 

컨텍스트 스위칭

CPU가 어떤 하나의 프로세스를 실행하고 있는 상태에서 인터럽트 요청에 의해 다음 우선 순위의 프로세스가 먼저 실행되어야 할 때, 기존의 프로세스 상태 또는 레지스터 값을 저장하고 CPU가 다음 프로세스를 수행하도록 새로운 프로세스의 상태 또는 레지스터 값을 교체하는 작업

 

동시에 실행할 수 있는 스레드 수는 코어수와 동일하다.

 

 

 

프로세스의 일부분씩 진행하는 것(컨텍스트 스위칭) 단일 코어 프로세서 혹은 멀티 코어에서 가능한 방식.

 

멀티 코어에서만 가능함.

www.wrapuppro.com/programing/view/jAuG3VNBCbGnQWU

velog.io/@agugu95/%EC%9E%90%EB%B0%94%EC%99%80-%EC%93%B0%EB%A0%88%EB%93%9C%ED%92%80-%EC%93%B0%EB%A0%88%EB%93%9C%EC%9D%98-%EC%83%9D%EC%84%B1%EB%B9%84%EC%9A%A9

kdata.or.kr/info/info_04_view.html?field=&keyword=&type=techreport&page=197&dbnum=127867&mode=detail&type=techreport

d2.naver.com/helloworld/10963

sjh836.tistory.com/151

honeymon.io/tech/2019/05/30/java-memory-leak-analysis.html

d2.naver.com/helloworld/1326256

 

n1tjrgns.tistory.com/243