Java 서버 배포 시 발생하는 주요 문제 및 해결 방안

회사 제품의 웹 서버 구축 및 유지보수를 담당하면서 최근 몇 가지 문제에 직면했습니다. 이 문제들을 정리하여 초보 개발자들이 같은 실수를 반복하지 않도록 도움을 드리고자 합니다.

첫 번째 문제: Tomcat 메모리 설정

일반적인 Java 메모리 오버플로우 유형:

  1. java.lang.OutOfMemoryError: Java heap space - JVM 힙(Heap) 오버플로우 JVM은 시작 시 자동으로 힙 메모리 값을 설정합니다. 초기 크기(-Xms)는 물리 메모리의 1/64이며, 최대 크기(-Xmx)는 물리 메모리를 초과할 수 없습니다.

-Xmn, -Xms, -Xmx 등 JVM 옵션을 사용하여 메모리 크기를 조정할 수 있습니다. 힙 크기는 Young Generation과 Tenured Generation의 합입니다.

JVM에서 98%의 시간이 GC에 사용되고, 사용 가능한 힙 크기가 2% 미만일 경우 이 예외가 발생합니다.

해결 방안: JVM 힙 크기를 수동으로 설정합니다.

  1. java.lang.OutOfMemoryError: PermGen space - PermGen 공간 오버플로우 PermGen space는 메모리의 영구 저장 영역을 의미합니다.

이 영역은 JVM이 Class와 메타 정보를 저장하는 공간입니다. Class가 로드될 때 PermGen space 영역에 저장되며, Instance가 저장되는 Heap 영역과 다릅니다. Sun의 GC는 프로그램 실행 중에 PermGen space를 정리하지 않으므로, 애플리케이션이 많은 CLASS를 로드할 경우 PermGen space 오버플로우가 발생할 수 있습니다.

해결 방안: MaxPermSize 값을 수동으로 설정합니다.

  1. java.lang.StackOverflowError - 스택 오버플로우 JVM은 스택 기반 가상 머신을 사용하며, 함수 호출 과정이 스택에 저장되고 복귀됩니다. 생성자 호출 "레이어"가 너무 많아 스택 영역이 오버플로우됩니다.

일반적으로 스택 영역은 힙 영역보다 훨씬 작습니다. 함수 호출 과정은 수천 레벨을 넘지 않으며, 각 함수 호출에 1KB 공간이 필요하더라도 스택 영역은 1MB 정도만 필요합니다. 일반적으로 스택 크기는 1-2MB입니다.

재귀 호출 시 재귀 레벨이 너무 깊어지면 스택 오버플로우가 발생하기 쉽습니다.

해결 방안: 프로그램 코드를 수정합니다.

Tomcat 시작 시 초기 메모리(-Xms)는 물리 메모리의 1/64, 최대 메모리(-Xmx)는 물리 메모리의 1/4로 설정합니다.

Linux:

# /usr/local/apache-tomcat-5.5.23/bin/catalina.sh 파일에 추가
JAVA_OPTS='-Xms512m -Xmx1024m'

-Xms: 초기값, -Xmx: 최대값, -Xmn: 최소값

Windows:

# catalina.bat 파일 맨 앞에 추가
set JAVA_OPTS=-Xms128m -Xmx350m

startup.bat로 Tomcat을 시작하면 설정이 적용되지만, Windows 서비스로 시작할 경우 설정이 적용되지 않습니다. Windows 서비스는 bin\tomcat.exe를 실행하며, 이는 catalina.bat 설정이 아닌 레지스트리 값을 읽습니다.

해결 방안:

# 레지스트리 수정: HKEY_LOCAL_MACHINE\SOFTWARE\Apache Software Foundation\Tomcat Service Manager\Tomcat5\Parameters\JavaOptions
# 기존 값에 추가: -Xms300m -Xmx350m

java.lang.OutOfMemoryError: PermGen space 문제는 Spring, Hibernate, Tomcat 등이 동적으로 클래스를 생성하여 JVM의 영구 힙 메모리가 오버플로우되기 때문에 발생합니다. Tomcat FAQ에서 이 문제의 근본 원인을 설명합니다. SUN JVM은 메모리를 다른 영역으로 나누며, 그중 하나가 PermGen 영역입니다. 이 영역은 자주 사용되는 클래스와 클래스 설명을 저장하는 공간입니다. SUN은 이 영역이 JVM 시작 시 고정될 것이라고 설계했지만, 동적 클래스 로딩이 널리 사용되면서 GC가 이 영역을 회수하지 못하는 문제가 발생했습니다.

해결 방안:

# catalina.bat 파일 첫 줄에 추가
set JAVA_OPTS=-Xms64m -Xmx256m -XX:PermSize=128M -XX:MaxNewSize=256m -XX:MaxPermSize=256m

# catalina.sh 파일 첫 줄에 추가
JAVA_OPTS=-Xms64m -Xmx256m -XX:PermSize=128M -XX:MaxNewSize=256m -XX:MaxPermSize=256m

두 번째 문제: 서버 메모리 사용률 90% 이상 지속

이 문제는 프로그램 코드에서 원인을 찾기 어려운 경우가 많습니다. 주로 서버 사양이 낮거나 Tomcat에서 실행되는 서비스가 너무 많아 서버 부하가 과도하게 발생하는 경우입니다.

해결 방안:

  1. 서버 사양 업그레이드 요청
  2. Tomcat 서비스를 여러 서버에 분산 배치
  3. 서버의 가상 메모리 크기 증가

가상 메모리 크기를 수동으로 늘리는 방법:

컴퓨터 아이콘 우클릭 → 속성 → 고급 시스템 설정 → 성능 옵션 → 고급 → 가상 메모리 → 변경

세 번째 문제: 서버 메모리 사용률 갑자기 99% 도달

이 문제는 sychost.exe 서비스가 상당한 메모리를 사용하는 경우 발생합니다. 이는 Windows 업데이트 서비스이지만, 바로 종료하면 블루스크린이 발생할 수 있습니다.

해결 방안: 시작 → 모든 프로그램 → 관리 도구 → 서비스에서 Windows Update 서비스를 수동으로 설정합니다.

태그: java Tomcat 메모리 관리 서버 배포 OutOfMemoryError

5월 29일 14:39에 게시됨