OS

[Linux] Apache-tomcat Out of Memory 란

파주상남자의 오답노트 ㅣ 2025. 4. 29. 16:08

반응형

📦 Tomcat Out of Memory (OOM) 오류

1. Out of Memory (OOM) 오류란?

Out of Memory (OOM) 오류는 **JVM (Java Virtual Machine)**이 할당된 메모리 용량을 초과해 더 이상 메모리를 할당할 수 없을 때 발생하는 오류입니다.

Tomcat 서버에서 자주 발생하는 OOM 오류는 대개 Java 애플리케이션이 너무 많은 메모리를 소비하거나 JVM의 메모리 설정이 부족할 때 나타납니다.


2. OOM 오류의 주요 원인

2.1. JVM 메모리 설정 부족

Tomcat은 Java 기반의 웹 서버이므로, JVM의 메모리 설정이 부족할 경우 애플리케이션이 사용할 수 있는 메모리가 부족해져서 OOM이 발생할 수 있습니다.

JVM에는 여러 종류의 메모리 영역이 있는데, 그 중 가장 중요한 두 가지는 **힙 메모리(heap memory)**와 **메타스페이스(Metaspace)**입니다.

  • 힙 메모리 (Heap Memory): 애플리케이션에서 사용하는 객체들이 저장되는 메모리 공간.
  • 메타스페이스 (Metaspace): 클래스 메타데이터가 저장되는 공간.

2.2. 메모리 누수 (Memory Leak)

애플리케이션에서 메모리 할당 후 해제되지 않거나, 필요 없는 객체를 계속해서 생성하고 해제하지 않으면 메모리 누수가 발생합니다.

이로 인해 시간이 지남에 따라 점점 더 많은 메모리를 소비하게 되어 OOM이 발생할 수 있습니다.

2.3. 불필요한 스레드 또는 연결

Tomcat에서 너무 많은 스레드나 DB 연결이 생성되면 메모리를 과도하게 소모하게 되어 OOM 오류가 발생할 수 있습니다.


3. Out of Memory (OOM) 오류 해결 방안

3.1. JVM 메모리 설정 변경

Tomcat이 실행되는 JVM의 힙 메모리, 메타스페이스 등을 조정하여 메모리 부족을 방지할 수 있습니다.

  • Tomcat에서 JVM 메모리 설정을 변경하는 방법: Tomcat의 메모리 설정은 $CATALINA_HOME/bin/setenv.sh (Linux/Unix) 또는 setenv.bat (Windows) 파일에서 설정할 수 있습니다.

예시: setenv.sh 파일 수정

export CATALINA_OPTS="-Xms512m -Xmx2048m -XX:MaxMetaspaceSize=512m"
  • -Xms512m: 초기 힙 메모리 크기 (512MB)
  • -Xmx2048m: 최대 힙 메모리 크기 (2048MB, 즉 2GB)
  • -XX:MaxMetaspaceSize=512m: 메타스페이스의 최대 크기 (512MB)

메모리 설정을 충분히 커지면 OOM을 예방할 수 있습니다. 그러나 너무 큰 값을 설정하면 시스템에 과도한 부담을 줄 수 있으므로 적절히 설정해야 합니다.


3.2. 메모리 누수 해결

메모리 누수는 대부분 코드에서 객체를 적절히 해제하지 않거나, 비효율적인 메모리 관리로 인해 발생합니다. 이를 해결하려면:

  • 애플리케이션 코드 검토: 객체를 다 사용한 후 명시적으로 null로 설정하거나, try-with-resources 구문을 사용하여 리소스를 자동으로 해제하도록 합니다.
  • 메모리 분석 도구 사용: VisualVM, Eclipse Memory Analyzer, jmap 등을 사용하여 메모리 사용 현황을 분석하고 메모리 누수 원인을 추적합니다.

예시:

jmap -heap <PID> # JVM 힙 메모리 분석
  • GC 로그 분석: -XX:+PrintGCDetails -XX:+PrintGCDateStamps 옵션을 사용하여 GC 로그를 확인하고, 메모리 누수나 과도한 가비지 컬렉션을 찾아낼 수 있습니다.

3.3. 불필요한 스레드/DB 연결 관리

Tomcat에서 스레드 풀이나 DB 연결 풀의 크기를 너무 크게 설정하면 메모리 부족을 초래할 수 있습니다.

  • 스레드 수 제한: Tomcat의 server.xml 파일에서 Connector 태그 내의 maxThreads 값을 적절하게 설정하여 처리할 수 있는 요청의 수를 제한합니다.
 
<Connector port="8080" protocol="HTTP/1.1" 
	connectionTimeout="20000" 
    	redirectPort="8443" 
        maxThreads="200" />
  • DB 연결 풀 설정: DB 연결을 잘 관리하지 않으면 불필요한 연결이 쌓여서 메모리 문제를 일으킬 수 있습니다. Tomcat JDBC Connection Pool을 사용하여 커넥션 풀의 최대 크기(maxActive)와 최소 크기(minIdle)를 설정할 수 있습니다.
<Context>
    <Resource name="jdbc/myDB"
              auth="Container"
              type="javax.sql.DataSource"
              maxActive="100"
              minIdle="10"
              username="dbuser"
              password="dbpassword"
              driverClassName="com.mysql.cj.jdbc.Driver"
              url="jdbc:mysql://localhost:3306/mydb" />
</Context>
 

3.4. JVM 옵션 추가

Tomcat의 성능을 최적화하기 위해 다양한 JVM 옵션을 추가할 수 있습니다.

  • 가비지 컬렉션 옵션 추가:G1 GC는 대형 힙을 가진 애플리케이션에 유리한 가비지 컬렉션 방식입니다. GC로 인한 OOM을 방지할 수 있습니다.
export CATALINA_OPTS="$CATALINA_OPTS -XX:+UseG1GC -XX:MaxGCPauseMillis=200"
  • Heap Dump 설정: OOM이 발생했을 때 Heap Dump를 자동으로 생성하여 원인 분석에 도움을 줄 수 있습니다.
export CATALINA_OPTS="$CATALINA_OPTS -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/path/to/heapdump.hprof"

4. 로그 분석 및 모니터링 도구 사용

  • JVM 로그 분석 도구: jstat, jmap 등을 사용하여 힙 메모리와 GC 동작을 분석할 수 있습니다.
  • 성능 모니터링 도구:
    • VisualVM: JVM 성능 분석 도구로 메모리 사용량, CPU 사용량, GC 상태 등을 모니터링합니다.
    • New Relic, Datadog 등 APM(Application Performance Management) 도구를 사용하여 애플리케이션의 메모리 사용 현황을 실시간으로 모니터링합니다.

5. 요약

원인 해결 방안
JVM 메모리 설정 부족 setenv.sh에서 -Xms, -Xmx 설정 조정
메모리 누수 코드 검토 및 메모리 분석 도구 사용 (VisualVM, Eclipse MAT 등)
스레드/DB 연결 관리 불량 server.xml의 maxThreads 및 DB 연결 풀 설정 최적화
가비지 컬렉션 이슈 G1 GC 및 JVM 옵션 추가
OOM 발생 시 분석 필요 Heap Dump, GC 로그 활성화 및 분석 도구 사용

6. OOM 발생 시 catalina.out 로그에 나타나는 내용

catalina.out 파일에는 JVM의 메모리 부족, 가비지 컬렉션 상태, 그리고 OOM 오류와 관련된 정보가 기록됩니다. OOM이 발생할 때 발생하는 일반적인 로그 항목은 다음과 같습니다.

예시 로그:

java.lang.OutOfMemoryError: Java heap space
    at java.util.ArrayList.ensureCapacity(ArrayList.java:169)
    at java.util.ArrayList.add(ArrayList.java:353)
    at com.example.myapp.SomeClass.someMethod(SomeClass.java:45)
    at com.example.myapp.MainClass.main(MainClass.java:12)
...

이 로그는 Java heap space 메모리 부족으로 인한 OOM 오류를 보여줍니다. 이는 힙 메모리가 부족하여 더 이상 객체를 할당할 수 없을 때 발생합니다.

7. OOM 관련 예시 로그 항목

  • Out of Memory Error (heap space):
java.lang.OutOfMemoryError: Java heap space
  • Metaspace 부족으로 인한 OOM:
java.lang.OutOfMemoryError: Metaspace
  • GC 로그가 함께 나오는 경우: OOM 오류가 발생하기 전에 가비지 컬렉션이 얼마나 이루어졌는지 확인할 수 있습니다.
[GC (Allocation Failure)  123456K->1234K(2048K), 0.0023456 secs]
[GC (Allocation Failure)  123456K->1234K(2048K), 0.0023456 secs]

8. OOM 오류 발생 후 흔히 나오는 GC 관련 로그

JVM은 메모리를 회수하기 위해 가비지 컬렉션(GC) 을 수행하는데, OOM 오류가 발생하기 전에 가비지 컬렉션이 발생하는 경우가 많습니다. 이때 GC의 로그가 포함될 수 있습니다.

예시:

[GC (Allocation Failure)  123456K->1234K(2048K), 0.0023456 secs]
[GC (Allocation Failure)  123456K->1234K(2048K), 0.0023456 secs]

이 로그에서는 GC가 실패했거나 메모리가 회수되지 않았음을 나타냅니다. OOM이 발생할 때마다 GC가 적절히 메모리를 회수하지 못하면 결국 OOM 오류로 이어집니다.

9. Out of Memory와 관련된 로그 패턴

  • OutOfMemoryError 메시지가 발생하면, StackTrace와 함께 오류가 발생한 클래스와 메서드 정보가 기록됩니다. 이를 통해 메모리 소비가 많아지는 위치를 확인할 수 있습니다.
  • GC 로그가비지 컬렉션이 얼마나 자주 수행되었고, 얼마나 메모리를 회수했는지에 대한 정보를 제공합니다.
  • 클래스 로딩 및 언로딩 문제가 메타스페이스 부족으로 OOM을 일으킬 수 있으므로, 메타스페이스 관련 오류가 있다면 JVM의 메타스페이스 설정을 조정해야 합니다.

10. OOM 로그 분석 방법

OOM 로그를 분석할 때는 다음과 같은 절차로 진행할 수 있습니다:

10.1. Stack Trace 분석

  • Stack Trace에서 오류가 발생한 지점(클래스와 메서드)을 추적하여 메모리 할당이 많은 곳을 찾아냅니다.
  • 특정 객체가 너무 많이 할당되고 있거나, 특정 메서드에서 반복적으로 메모리 할당이 발생하고 있는지 확인합니다.

10.2. GC 로그 분석

  • 가비지 컬렉션을 확인하여 메모리가 얼마나 회수되었는지 확인하고, GC가 제대로 동작하지 않거나 자주 발생하는지 점검합니다.
  • GC 시간이 너무 길어지면 애플리케이션이 느려지거나 OOM을 유발할 수 있습니다. -XX:+PrintGCDetails 옵션을 사용하여 GC 상태를 더욱 세밀하게 분석할 수 있습니다.

10.3. Heap Dump

OOM이 발생할 때 Heap Dump를 생성하는 설정을 추가하면, 메모리 덤프 파일을 분석하여 메모리 누수 문제를 더 잘 파악할 수 있습니다. -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/path/to/dumpfile 옵션을 사용하여 자동으로 덤프 파일을 생성하게 할 수 있습니다.

export CATALINA_OPTS="$CATALINA_OPTS -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/path/to/heapdump.hprof"

11. catalina.out 로그에서의 OOM 관련 예시

  • 메모리 부족(Heap space) 예시:
java.lang.OutOfMemoryError: Java heap space
    at java.util.ArrayList.ensureCapacity(ArrayList.java:169)
    at java.util.ArrayList.add(ArrayList.java:353)
    at com.example.myapp.SomeClass.someMethod(SomeClass.java:45)
    at com.example.myapp.MainClass.main(MainClass.java:12)
  • 메타스페이스 부족 예시:
java.lang.OutOfMemoryError: Metaspace
    at java.lang.ClassLoader.defineClass1(Native Method)
    at java.lang.ClassLoader.defineClass(ClassLoader.java:760)
    at org.apache.catalina.loader.WebappClassLoaderBase.findClassInternal(WebappClassLoaderBase.java:235)
    at org.apache.catalina.loader.WebappClassLoaderBase.findClass(WebappClassLoaderBase.java:156)
    at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:141)
    at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:129)

12. 로그 파일 위치

Tomcat의 catalina.out 파일은 Tomcat 로그 디렉토리에 저장됩니다. 일반적으로 Tomcat의 로그는 /logs 디렉토리에 저장됩니다.

  • 로그 경로 예시:
  •  
/path/to/tomcat/logs/catalina.out

13. 요약

  • OOM 발생 시 catalina.out 로그에 OutOfMemoryError 또는 GC 로그가 포함됩니다.
  • 메모리 부족 문제를 해결하려면 JVM 메모리 설정, 메모리 누수 분석, GC 로그 분석, Heap Dump 분석을 통해 원인을 추적할 수 있습니다.
  • Heap DumpGC 로그 분석을 통해 애플리케이션에서의 메모리 소비 문제를 해결할 수 있습니다.
반응형