반복영역 건너뛰기
주메뉴 바로가기
본문 바로가기
제품/서비스
EMS Solution
Features
클라우드 관리
AI 인공지능
서버관리
데이터베이스 관리
네트워크 관리
트래픽 관리
설비 IoT 관리
무선 AP 관리
교환기 관리
운영자동화
실시간 관리
백업 관리
APM Solution
애플리케이션 관리
URL 관리
ITSM Solution
서비스데스크
IT 서비스 관리
Big Data Solution
SIEM
Dashboard
대시보드
Consulting Service
컨설팅 서비스
고객
레퍼런스
고객FAQ
문의하기
가격
자료실
카탈로그
사용자매뉴얼
회사소개
비전·미션
연혁
2016~현재
2000~2015
인증서·수상
투자정보
재무정보
전자공고
IR자료
새소식
공고
보도자료
오시는 길
채용
피플
컬처
공고
FAQ
블로그
열기
메인 페이지로 이동
블로그
최신이야기
블로그
최신이야기
사람이야기
회사이야기
기술이야기
다양한이야기
카프카를 통한 로그 관리 방법
메모리 누수 위험있는 FinalReference 참조 분석하기
김진광
2023.10.12
페이스북 공유하기
트위터 공유하기
링크드인 공유하기
블로그 공유하기
[행사] 브레인즈컴퍼니 ‘가을문화행사 2023’
Java에서 가장 많이 접하는 문제는 무엇이라 생각하시나요? 바로 리소스 부족 특히 ‘JVM(Java Virtual Machine) 메모리 부족 오류’가 아닐까 생각해요.
메모리 부족 원인에는 우리가 일반적으로 자주 접하는 누수, 긴 생명주기, 다량의 데이터 처리 등 몇 가지 패턴들이 있는데요. 오늘은 좀 일반적이지 않은(?) 유형에 대해 이야기해 볼게요!
Java 객체 참조 시스템은 강력한 참조 외에도 4가지 참조를 구현해요. 바로 성능과 확장성 기타 고려사항에 대한 SoftReference, WeakReference, PhantomReference, FinalReference이죠. 이번 포스팅은
FinalReference를 대표적인 사례
로 다루어 볼게요.
PART1. 분석툴을 활용해 메모리 누수 발생 원인 파악하기
메모리 분석 도구를 통해 힙 덤프(Heap Dump)를 분석할 때, java.lang.ref.Finalizer 객체가 많은 메모리를 점유하는 경우가 있어요. 이 클래스는 FinalReference와 불가분의 관계에요. 나눌 수 없는 관계라는 의미죠.
아래 그림 사례는 힙 메모리(Heap Memory)의 지속적인 증가 후 최대 Heap에 근접 도달 시, 서비스 무응답 현상에 빠지는 분석 사례인데요. 이를 통해 FinalReference 참조가 메모리 누수를 발생시킬 수 있는 조건을 살펴볼게요!
Heap Analyzer 분석툴을 활용하여, 힙 덤프 전체 메모리 요약 현황을 볼게요. java.lang.ref.Finalizer의 점유율이 메모리의 대부분을 점유하고 있죠. 여기서 Finalizer는, 앞에서 언급된 FinalReference를 확장하여 구현한 클래스에요.
JVM은 GC(Garbage Collection) 실행 시 해제 대상 객체(Object)를 수집하기 전, Finalize를 처리해야 해요.
Java Object 클래스에는 아래 그림과 같이 Finalize 메서드(Method)가 존재하는데요. 모든 객체가 Finalize 대상은 아니에요.
JVM은 클래스 로드 시, Finalize 메서드가 재정의(Override)된 객체를 식별해요. 객체 생성 시에는 Finalizer.register() 메서드를 통해, 해당 객체를 참조하는 Finalizer 객체를 생성하죠.
그다음은 Unfinalized 체인(Chain)에 등록해요. 이러한 객체는 GC 발생 시 즉시 Heap에서 수집되진 않아요. Finalizer의 대기 큐(Queue)에 들어가 객체에 재정의된 Finalize 처리를 위해 대기(Pending) 상태에 놓여있죠.
위 그림과 같이 참조 트리(Tree)를 확인해 보면, 많은 Finalizer 객체가 체인처럼 연결되어 있어요. 그럼 Finalizer 객체가 실제 참조하고 있는 객체는 무엇인지 바로 살펴볼까요?
그림에 나온 바와 같이 PostgreSql JDBC Driver의 org.postgresql.jdbc3g.Jdbc3gPreparedStatement인 점을 확인할 수 있어요. 해당 시스템은 PostgreSql DB를 사용하고 있었네요.
이처럼 Finalizer 참조 객체 대부분은 Jdbc3gPreparedStatement 객체임을 알 수 있어요. 여기서 Statement 객체는, DB에 SQL Query를 실행하기 위한 객체에요.
그렇다면, 아직 Finalize 처리되지 않은 Statement 객체가 증가하는 이유는 무엇일까요?
먼저 해당 Statement 객체는 실제로 어디서 참조하는지 살펴볼게요. 해당 객체는 TimerThread가 참조하는 TaskQueue에 들어가 있어요. 해당 Timer는 Postgresql Driver의 CancelTimer이죠.
해당 Timer의 작업 큐를 확인해 보면 PostgreSql Statement 객체와 관련된 Task 객체도 알 수도 있어요.
그럼 org.postgresql.jdbc3g.Jdbc3gPreparedStatement 클래스가 어떻게 동작하는지 자세히 알아볼까요?
org.postgresql.jdbc3g.Jdbc3gPreparedStatement는 org.postgresql.jdbc2.AbstractJdbc2Statement의 상속 클래스이며 finalize() 메서드를 재정의한 클래스에요. Finalize 처리를 위해 객체 생성 시, JVM에 의해 Finalizer 체인으로 등록되죠.
위와 같은 코드로 보아 CancelTimer는, Query 실행 후 일정 시간이 지나면 자동으로 TimeOut 취소 처리를 위한 Timer에요.
정해진 시간 내에 정상적으로 Query가 수행되고 객체를 종료(Close) 시, Timer를 취소하도록 되어 있어요. 이때 취소된 Task는 상태 값만 변경되고, 실제로는 Timer의 큐에서 아직 사라지진 않아요.
Timer에 등록된 작업은, TimerThread에 의해 순차적으로 처리돼요. Task는 TimerThread에서 처리를 해야 비로소 큐에서 제거되거든요.
이때 가져온 Task는 취소 상태가 아니며, 처리 시간에 아직 도달하지 않은 경우 해당 Task의 실행 예정 시간까지 대기해야 돼요.
여기서 문제점이 발생해요.
이 대기 시간이 길어지면 TimerThread의 처리가 지연되기 때문이죠. 이후 대기 Task들은 상태 여부에 상관없이, 큐에 지속적으로 남아있게 돼요.
만약 오랜 시간 동안 처리가 진행되지 않는다면, 여러 번의 Minor GC 발생 후 참조 객체들은 영구 영역(Old Gen)으로 이동될 수 있어요.
영구 영역으로 이동된 객체는, 메모리에 즉시 제거되지 못하고 오랜 기간 남게 되죠. 이는 Old(Full) GC를 발생시켜 시스템 부하를 유발하게 해요. 실제로 시스템에 설정된 TimeOut 값은 3,000초(50분)에요.
Finalizer 참조 객체는 GC 발생 시, 즉시 메모리에서 수집되지 않고 Finalize 처리를 위한 대기 큐에 들어가요. 그다음 FinalizerThread에 의해 Finalize 처리 후 GC 발생 시 비로소 제거되죠. 때문에 리소스의 수집 처리가 지연될 수 있어요.
또한 FinalizerThread 스레드는 우선순위가 낮아요. Finalize 처리 객체가 많은 경우, CPU 리소스가 상대적으로 부족해지면 개체의 Finalize 메서드 실행을 지연하게 만들어요. 처리되지 못한 객체는 누적되게 만들죠.
요약한다면 FinalReference 참조 객체의 잘못된 관리는
1) 객체의 재 참조를 유발 2) 불필요한 객체의 누적을 유발 3) Finalize 처리 지연으로 인한 리소스 누적을 유발
하게 해요.
PART2.
제니우스 APM을 통해 Finalize 객체를 모니터링하는 방법
Zenius APM에서는 JVM 메모리를 모니터링하고 분석하기 위한, 다양한 데이터를 수집하고 있어요. 상단에서 보았던
FinalReference 참조 객체의 현황에 대한 항목도 확인
할 수 있죠.
APM 모니터링을 통해 Finalize 처리에 대한 문제 발생 가능성도
‘사전’
에 확인
할 수 있답니다!
위에 있는 그림은 Finalize 처리 대기(Pending)중인 객체의 개수를 확인 가능한 컴포넌트에요.
이외에도 영역별 메모리 현황 정보와 GC 처리 현황에 대해서도 다양한 정보를 확인 할 수 있어요!
이상으로 Finalize 처리 객체에 의한 리소스 문제 발생 가능성을, 사례를 통해 살펴봤어요. 서비스에 리소스 문제가 발생하고 있다면, 꼭 도움이 되었길 바라요!
------------------------------------------------------------
©참고 자료
◾ uxys, http://www.uxys.com/html/JavaKfjs/20200117/101590.html
◾ Peter Lawrey, 「is memory leak? why java.lang.ref.Finalizer eat so much memory」, stackoverflow, https://stackoverflow.com/questions/8355064/is-memory-leak-why-java-lang-ref-finalizer-eat-so-much-memory
◾ Florian Weimer, 「Performance issues with Java finalizersenyo」, enyo,
https://www.enyo.de/fw/notes/java-gc-finalizers.html
------------------------------------------------------------
#APM
#Finalize
#제니우스
#메모리 누수
#Zenius
#FinalReference
#제니우스 APM
김진광
APM팀(개발3그룹)
개발3그룹 APM팀에서 제품 개발과 기술 지원을 담당하고 있습니다.
필진 글 더보기
목록으로
추천 콘텐츠
이전 슬라이드 보기
브레인저가 되면 누릴 수 있는 것들 ㅣ (4) 동호회 편
브레인저가 되면 누릴 수 있는 것들 ㅣ (4) 동호회 편
브레인즈컴퍼니는 브레인저들이 일에만 묻혀 지내지 않고, 동료와 교류를 통해 일상에 활력을 불어넣을 수 있도록 사내 동호회를 운영하고 있습니다. 동호회 활동은 단순한 놀이에 그치지 않고, 자연스럽게 업무에도 적용되고 있는데요. 서로 다른 팀의 동호회원들은 끈끈한 동료애를 바탕으로, 협업 시 서로 배려하며 협동심을 발휘할 수 있습니다. 동호회는 업무와 별개인 것 같아 보이지만, 타 부서와의 소통을 통해 업무 생산성을 올릴 수 있는 수단이 되기도 합니다. 이를 통해 브레인저들은 더욱 행복한 회사 생활을 할 수 있겠죠? 브레인즈컴퍼니는 동호회 활동에 지원을 아끼지 않고 있습니다. 5인 이상이 모이면 누구든지 동호회를 만들 수 있고, 사측에서는 달마다 인당 활동비를 지원하고 있는데요. (선근님이 본인 지갑을 열 때도 있다는 소문이...) 브레인즈컴퍼니의 동호회 활동을 살펴볼까요? 첫 번째로, 보드게임 동호회 '하드보드지' "열심히 보드게임 하지"라는 뜻의 하드보드지는 2016년 12월에 인프라코어팀 용관님의 제안으로 만들어진 동호회입니다. 현재 동호회 회장은 인프라코어팀 동조님이, 총무는 용관님이 맡고 있습니다. 하드보드지의 멤버는 총 13명으로, 인프라코어팀을 비롯해 TC팀, 프리세일즈팀, 영업그룹, 경영기획실 등 다양한 부서와 직급으로 구성돼있습니다. 하드보드지는 보통 한 달에 2~3회 정도 모여 게임을 즐긴다고 하는데요. 플레이타임이 20~30분 정도일 땐 점심 시간을, 30분 이상인 게임을 할 땐 퇴근 이후 시간을 활용한다고 해요. 점심 시간에는 여러 명이 간단하게 즐길 수 있는 텔레스트레이션, 디렉사우, 다크호스, 애비뉴, 사보타지, 스시고파티, 텀블링 다이스 등의 파티게임 위주로 하고, 저녁 시간대는 여유롭다 보니 파티게임뿐만 아니라 데드오브윈터, 모노폴리, 클루, 티켓투라이드, 카르카손, 뱅, 돌팔이약장수 등의 게이머스한 보드게임을 즐긴다고 하네요. 총무 용관님은 보드게임의 매력에 대해 "게임을 보기만 하지 않고 직접 만지고 굴려가며, 같이 플레이하는 사람들과 대화를 하면서 즐길 수 있어요. 또 남녀노소 모두 함께 즐길 수 있다는 것이 큰 장점입니다"라고 전해왔습니다. 필자도 올 1월에 하드보드지에 가입했는데요. 퇴근 후 동료들과 함께 게임을 즐기다 보면, 어느새 스트레스가 해소되는게 느껴졌습니다. 또, 평소 얼굴만 알고 지내던 동료들과 좀 더 친해질 수 있는 계기가 되기도 했고, 끈끈한 동료애가 생기는 것 같아 좋았습니다. 특히, 이번에 가입하면서 생각치도 못했던 보드게임을 선물 받아 설 연휴 때 가족들과 함께 게임을 즐겼습니다. 다음 게임이 또 기다려집니다! :) 두 번째로, 일상에 활력을 불어 넣어 준다는 '풋살 동호회' 풋살 동호회는 2018년 전략사업본부 회식 때 이야기가 나와 만들어 졌다는데요. 주로 TC팀과 영업팀 위주로 구성됐고, 회장 정대님의 운영 하에 13명의 멤버가 활동하고 있다고 합니다. 경기는 월 1회 정도, 주로 목요일 저녁 7시에 진행하고 있습니다. 정대님은 풋살의 매력에 대해 "직장 생황을 하며 운동을 하기가 참 쉽지 않습니다. 더욱이 혼자라면 엄두가 안 나죠. 브레인즈의 풋살 동호회는 한 달에 한 번 정도 부담가지 않는 선에서, 중고등학교 시절처럼 공 하나 놓고 즐기는 분위기로 운영되고 있어요. 그래서 꼭 운동 목적이 아니더라도 일상에 활력이 필요한 분들에게 적극 권유드려요"라고 전해왔습니다. 다들 체력이 좋지 않아, 10분 경기하고 20분 간 경기장에 드러누워 있었던 적도 있다고 하네요. 이처럼 풋살 동호회는 건강 뿐만 아니라 소통과 친목을 위해 진행되고 있으니 실력과 체력에 자신이 없는 분들도 자유롭게 참여할 수 있다고 해요. 풋살 경험이 없어 망설이고 있다면, 일단 가입하시고 가장 풋살을 잘하고 득점을 많이 한 멤버인 TC팀 기열님에게 배워봐도 좋을 것 같아요! 이처럼 브레인저들은 동호회 활동을 통해 행복한 회사 생활을 하고 있습니다. 이 글을 읽고 있는 예비 브레인저 분들! 브레인즈컴퍼니에 합류하게 된다면, 동호회에 가입하고 끈끈한 동료애를 쌓아가시길 바랍니다!
2023.01.27
[행사] 2023년 3월 BB데이
[행사] 2023년 3월 BB데이
3월 BB데이가 29일에 열렸습니다! 이번 BB데이에는 역대 가장 많은 인원이 참석했는데요. 벚꽃엔딩을 주제로 한만큼 행사장 입구부터 벚꽃길을 걸을 수 있고, 식기와 먹을거리 등에도 벚꽃과 함께 봄이 내려앉았습니다. 행사 전 설문조사에서 브레인저들이 가장 선호하는 음식인 치킨! 매번 새로운 치킨을 맛보고 있요. 이번에는 맛집이 많은 성수에서 직접 공수해 온 바베큐 치킨을 준비했습니다. 신규 입사자들이 원한 분식과 맥주도 함께! 최근 브레인즈에 신규 입사자들이 많이 발생했는데요. 입사한 첫 달에는 동료들과 인사를 나누기 위해 대부분 BB데이에 참석하고 있고, 재참석률도 높은 편입니다. 같은 직급끼리, 또는 사수나 상사와 함께 참석해 즐거운 시간을 보내고 있습니다! 브레인저가 있는 곳에 빠질 수 없는 선근님 이날도 참석해서 브레인저들과 잠깐 술 한 잔하고, 불편해할까봐 금세 자리를 비우셨어요. 이번 BB데이에는 벚꽃 2행시를 짓는 이벤트를 준비했습니다. 이달에 입사한 개발4그룹의 채욱님이 상품을 받아갔어요. 그리고 행사 콘셉트에 맞춰 준비한 벚꽃잔을 가져 간 브레인저도 있었습니다. 그리고 이날은 특별히, 사내 보드게임 동호회 '하드보드지' 멤버들이 BB데이에 단체로 참석했다가, 행사가 끝난 후 모여서 보드게임을 즐기다 돌아갔습니다. 역대 많은 인원들이 모여, 평소 잘 몰랐던 브레인저들 간 서로 인사를 나누기도 하고 서로 어떤 일을 하는지에 대해서도 이야기 나누며 알찬 시간을 보냈습니다! 다음 달이면, BB데이가 1주년을 맞이합니다. 4월 BB데이도 기대해주세요.
2023.03.30
다음 슬라이드 보기