웹 서버 로 하여 금 outofmemory 를 피하 게 하 다
1. 하나의 filter 를 설정 하고 모든 사용자 의 요청 은 filter 의 filter 방법 으로 처 리 됩 니 다.
2 매번 filter 방법 이 호출 될 때마다 jvm 의 힙 메모리 사용 상황 을 검사 합 니 다. 힙 메모리 사용률 이 80% 이상 이 되면 System. gc () 를 호출 하고 접근 을 거부 하 며 503 오 류 를 되 돌려 클 라 이언 트 에 알 립 니 다.
코드 는 다음 과 같 습 니 다:
private void checkServerMemoryUsage() {
MemoryMXBean aMemoryMXBean=ManagementFactory.getMemoryMXBean();
MemoryUsage heapMemoryUsage=aMemoryMXBean.getHeapMemoryUsage();
long usedHeapMemory = heapMemoryUsage.getUsed();
long maxHeapMemory = heapMemoryUsage.getMax();
double MemUsedRate = (usedHeapMemory*1.0)/maxHeapMemory;
if(MemUsedRate >= 0.8) {
System.gc();
logger.error("Heap memory will be expired. Used Memory is: "+maxHeapMemory+" bytes. The max heap memory is: "+maxHeapMemory+" bytes.");
throw new RestException(503, "Server is too busy!");
}
}
원래 이렇게 하 는 것 이 문제 가 없다 고 생각 했 지만 나중에 디 버 깅 과정 에서 이런 현상 을 발견 했다.
10 개의 클 라 이언 트 를 시 뮬 레이 션 하고 server 에 요청 합 니 다. 모든 클 라 이언 트 가 제출 한 데 이 터 는 5M 입 니 다. 모든 클 라 이언 트 는 5000 번 연속 으로 보 냅 니 다. 실행 과정 에서 - verbosegc 옵션 을 열 었 습 니 다. 시작 할 때 상황 이 정상 적 이 고 gc 동작 이 자주 진행 되 었 습 니 다. (이것 은 신세대 Eden 구역 이 자주 꽉 차 서 minor GC 를 촉발 한 것 입 니 다)백 스테이지 에서 사용자 가 제출 한 데 이 터 를 책임 지고 처리 하기 때문에 새로운 대상 이 많이 생 길 수 있 기 때문에 이미 사용 한 구역 이 점점 커지 지만 사용률 이 80% 에 이 르 렀 을 때 System. gc () 를 명시 적 으로 호출 했 습 니 다. 이 럴 때 시스템 은 full gc 를 실행 하고 클 라 이언 트 도 503 오 류 를 받 을 수 있 습 니 다.모든 것 이 비교적 완벽 해 보인다.
내 가 모든 클 라 이언 트 스 레 드 를 kill 로 떨 어 뜨 렸 을 때 문제 가 발생 했 습 니 다. 힙 의 점용 율 은 아직도 천천히 증가 하고 있 습 니 다 (앞에서 제출 한 데이터 가 아직 처리 되 고 있 을 수 있 기 때 문 입 니 다). 그러나 minor gc 는 촉발 되 지 않 았 습 니 다 (Eden 구역 이 채 워 지지 않 으 면 촉발 되 지 않 습 니 다). 이 를 통 해 대량의 대상 이 늙 은 세대 (Old generation) 에 있 고 늙 은 세대 가 가득 쓰 이지 않 으 며 full gc 를 촉발 하지 않 습 니 다.(기본 설정 은 1 시간 에 한 번 씩 full gc 를 실행 합 니 다) 이 때 힙 의 사용률 은 장기 적 으로 높 은 위치 로 유 지 됩 니 다.
그래서 개선 방안 이 나 타 났 습 니 다.
쓰다
static class MemoryInfo{
long usedHeapMemory;
long maxHeapMemory;
double getUsageRate(){
return (usedHeapMemory*1.0)/maxHeapMemory;
}
}
private void checkServerMemoryUsage() {
MemoryInfo info = getHeapUssageRate();
if(info.getUsageRate() >= 0.8) {
System.gc();
info = getHeapUssageRate();
if(info.getUsageRate() >= 0.8) {
logger.error("Heap memory will be expired. Used Memory is: "+info.usedHeapMemory+" bytes. The max heap memory is: "+info.maxHeapMemory+" bytes.");
throw new RestException(503, "Server is too busy!");
}
}
}
private MemoryInfo getHeapUssageRate() {
MemoryInfo info = new MemoryInfo();
MemoryMXBean aMemoryMXBean=ManagementFactory.getMemoryMXBean();
MemoryUsage heapMemoryUsage=aMemoryMXBean.getHeapMemoryUsage();
info.usedHeapMemory = heapMemoryUsage.getUsed();
info.maxHeapMemory = heapMemoryUsage.getMax();
return info;
}
요청 이 올 때마다 hep 사용 상황 을 확인 하고 사용률 이 80% 에 이 르 면 즉시 Sytem. gc () 를 호출 하여 full gc 를 실행 합 니 다. 그리고 사용률 이 80% 를 초과 하 는 지 다시 판단 합 니 다. 초과 하면 서 비 스 를 거부 하고 503 오 류 를 되 돌려 줍 니 다.
추가 개선:
full gc 는 시간 이 오래 걸 리 기 때문에 서버 의 성능 에 영향 을 줄 수 있 습 니 다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
자바 문자열 풀우리는 Java에서 문자열이 힙 메모리 영역에 저장된다는 것을 알고 있습니다. 이 힙 메모리 내부에는 String Pool이라는 특정 메모리 영역이 있습니다. 문자열 프리미티브를 생성하면 자바 문자열의 불변성 덕분에...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.