목차
기본 구성에서 JVM GC의 성능
分代垃圾回收的基本思想与堆内存大小调整
优化新生代内存大小
避免老年代GC的长时间暂停
Java java지도 시간 미션 크리티컬 Java 애플리케이션을 위한 가비지 수집 최적화에 대한 자세한 설명(1부)

미션 크리티컬 Java 애플리케이션을 위한 가비지 수집 최적화에 대한 자세한 설명(1부)

Mar 23, 2017 am 11:01 AM

최근에는 Sun/Oracle JVM에서 실행되는 여러 Java 기반 쇼핑 및 포털 애플리케이션을 테스트하고 최적화할 기회가 있었습니다. 가장 많이 방문한 앱은 독일에 있습니다. 많은 경우 가비지 수집은 Java 서버 성능에 중요한 요소입니다. 이 기사에서는 몇 가지 고급 가비지 수집 알고리즘 아이디어와 몇 가지 중요한 조정 매개변수를 연구합니다. 다양한 실제 시나리오에서 이러한 매개변수를 비교합니다.

가비지 수집 관점에서 볼 때 Java 서버 프로그램에는 다양한 요구 사항이 있을 수 있습니다.

  1. 일부 트래픽이 많은 애플리케이션은 많은 양의 데이터에 응답해야 합니다. 요청을 처리하고 매우 많은 개체를 생성합니다. 때로는 높은 리소스 소비 프레임워크를 사용하는 일부 중간 트래픽 애플리케이션에서 동일한 문제가 발생합니다. 즉, 이렇게 생성된 개체를 효과적으로 정리하는 방법은 가비지 수집에 있어서 큰 과제입니다.

  2. 또한 일부 애플리케이션은 장시간 실행되어야 하며, 운영 중에도 안정적인 서비스를 제공해야 하므로 시간이 지남에 따라 성능이 서서히 저하되거나 갑자기 저하되지 않아야 합니다.

  3. 일부 시나리오에서는 사용자 응답 시간에 대한 엄격한 제한이 필요하며(예: 온라인 게임 또는 베팅 애플리케이션) 추가 GC 일시 중지가 거의 허용되지 않습니다.

많은 시나리오에서 여러 요구사항을 서로 다른 우선순위와 결합할 수 있습니다. 내 샘플 프로그램 중 일부는 두 번째 지점보다 첫 번째 지점에 대한 요구 사항이 훨씬 높지만 대부분의 프로그램은 세 가지 측면 모두에 대해 동시에 높은 요구 사항을 갖고 있지 않습니다. 이로 인해 절충의 여지가 많이 남게 됩니다.

기본 구성에서 JVM GC의 성능

JVM은 많은 개선이 있었지만 여전히 프로그램이 실행되는 동안 작업을 최적화할 수 없습니다. 위에서 언급한 세 가지 사항 외에도 기본 JVM 설정에는 메모리 사용량 감소라는 두 번째 우선 순위가 있습니다. 메모리가 충분한 서버에서 수천 명의 사용자가 실행되고 있지 않다는 점을 고려하십시오. 또한 이러한 애플리케이션은 상용 서버가 아닌 대부분의 경우 개발 랩톱에서 실행되도록 구성되어 있기 때문에 많은 전자 상거래 제품에 있어서도 중요합니다. 따라서 서버가

java -Xmx1024m -XX:MaxPermSize=256m -cp Portal.jar my.portal.Portal
로그인 후 복사

와 같이 최소 힙 공간과 GC 매개변수로 구성된 경우 시스템이 비효율적으로 실행될 수 있습니다. 첫째, 서버가 시작하는 동안 점차적으로 메모리가 늘어나는 것을 방지하기 위해 최대 메모리 제한뿐만 아니라 초기 메모리 크기도 구성하는 것이 좋습니다. 그렇지 않으면 비용이 매우 많이 들 것입니다. 서버에 필요한 메모리 양을 알게 되면(그리고 시간이 지나면 알아내야 함) 초기 메모리 크기를 최대 메모리 설정과 동일하게 만드는 것이 가장 좋습니다. 다음 JVM 매개변수를 통해 설정할 수 있습니다.

-Xms1024m -XX:PermSize=256m
로그인 후 복사

JVM에서 자주 구성되는 마지막 기본 옵션은 위에서 설정한 방식과 유사하게 차세대 힙 메모리 크기를 구성하는 것입니다.

-XX:NewSize=200m -XX:MaxNewSize=200m
로그인 후 복사

다음 장에서는 위 구성과 더 복잡한 구성에 대해 설명합니다. 먼저 상당히 느린 테스트 호스트에서 실행되는 포털 애플리케이션을 살펴보겠습니다. 로드 테스트를 수행할 때 가비지 수집은 어떻게 작동합니까?

그림 1 약 25시간 동안 약간 최적화된 힙 크기를 사용한 JVM의 GC 동작(-Xms1024m - Xmx1024m -XX: NewSize=200m -XX:MaxNewSize=200m)

이 중 파란색 곡선은 시간에 따른 총 힙 메모리 사용량의 변화를 나타내고, 회색 세로선은 GC 일시정지 간격을 나타냅니다.

그래프 외에 가장 오른쪽에는 GC 운영의 주요 지표와 성과가 표시됩니다. 먼저 이 테스트 중에 생성된(및 수집된) 가비지의 평균 양을 살펴보겠습니다. 30.5MB/s 값은 노란색으로 표시됩니다. 이는 규모가 크지만 허용 가능한 가비지 생성 속도이며 입문 GC 튜닝 예제에 적합하기 때문입니다. 다른 값은 이 쓰레기를 정리하는 JVM의 성능을 나타냅니다. 새 세대에서는 쓰레기의 99.55%가 정리되고 이전 세대에서는 0.45%만 정리됩니다. 이 결과는 꽤 좋으므로 녹색으로 표시됩니다.

이러한 결과의 이유는 GC(및 사용자 요청을 처리하는 작업자 스레드)에서 도입한 일시 중지 간격에서 볼 수 있습니다. 차세대 GC 간격은 많지만 매우 짧습니다. 평균적으로 6초에 한 번입니다. 지속 시간은 50ms를 넘지 않습니다. 이러한 일시 중지로 인해 전체 시간의 0.77% 동안 JVM이 중지되었지만 각 일시 중지는 서버의 응답을 기다리는 사용자가 전혀 인지할 수 없었습니다.

반면, Old Generation GC Pause는 전체 시간의 0.19%만을 차지합니다. 하지만 이 기간 동안 구세대 GC는 0.45%의 쓰레기만 청소한 반면, 신세대 GC는 0.77%의 시간을 들여 99.55%의 쓰레기를 청소했다. 신세대 GC에 비해 구세대 GC가 얼마나 비효율적인지 알 수 있다. 또한, 구세대 GC 일시중지의 평균 트리거 속도는 시간당 1회 미만이지만 평균 지속 시간은 8초에 도달할 수 있고 최대 이상치는 19초에 달합니다. 이러한 일시 중지는 실제로 사용자 요청을 처리하는 JVM 스레드를 중지하므로 일시 중지는 가능한 한 드물고 지속 시간이 짧아야 합니다.

위의 관찰을 통해 세대별 가비지 수집의 기본 튜닝 목표를 도출할 수 있습니다.

  • 신세대 GC는 빈번한 가비지 수집을 피하기 위해 최대한 많은 가비지를 수집해야 합니다. 이전 세대에서는 GC가 자주 발생합니다.

分代垃圾回收的基本思想与堆内存大小调整

先从下图开始。这个图可以通过JDK工具得到,比如jstat或者jvisualvm以及它的visualgc插件:

图2 JVM的堆内存结构,包括新生代的子分区(最左列)

Java的堆内存由永久代(Perm),老年代(Old)和新生代(New or Young)组成。新生代进一步划分为一个Eden空间和两个Survivor空间S0、S1。Eden空间是对象被创建时的地方,经过几轮新生代GC后,他们有可能被存放在Survivor空间。如果想了解更多,可以读一下Sun/Oracle的白皮书Memory Management in the Java HotSpot Virtual Machine

默认情况下,作为整体的新生代特别是Survivor空间太小,导致在GC清理大部分内存之前就无法保存更多对象。因此,这些对象被过早地保存在老年代中,这会导致老年代被迅速填满,必须频繁地清理垃圾。这也是图1中产生较多的Full GC暂停的原因。

(译者注:一般新生代的垃圾回收也称为Minor GC,老年代的垃圾回收称为Major GC或Full GC)

优化新生代内存大小

优化分代垃圾回收意味着让新生代,特别是Survivor空间,比默认情形大。但是同时也要考虑虚拟机使用的具体GC算法。

当前硬件上运行的Sun/Oracle虚拟机使用了ParallelGC作为默认GC算法。如果使用的不是默认算法,可以通过显式配置JVM参数来实现:

-XX:+UseParallelGC
로그인 후 복사

默认情况下,这个算法并不在固定大小的Eden和Survivor空间中运行。它使用了一种自适应调整大小的策略,称为“AdaptiveSizePolicy”策略。正如描述的那样,它可以适应很多场景,包括服务器以外的机器的使用。但在服务器上运行时,这并不是最优策略。为了可以显式地设置固定的Survivor空间大小,可以通过以下JVM参数关闭它:

-XX:-UseAdaptiveSizePolicy
로그인 후 복사

一旦这么设置后,就不能进一步增加新生代空间的大小,但我们可以有效地为Survivor空间设置合适的大小:

-XX:NewSize=400m -XX:MaxNewSize=400m -XX:SurvivorRatio=6
로그인 후 복사

“SurvivorRatio=6”表示Survivor空间是Eden空间的1/6或者是整个新生代空间的1/8,在这个例子中就是50MB,而自适应大小策略经常运行在非常小的空间上,大约只有几MB。使用现在的配置,重复上面的负载测试,我们得到了下面的结果:

图3 堆内存优化后的JVM在50小时内的GC行为(-Xms1024m -Xmx1024m -XX:NewSize=400m -XX:MaxNewSize=400m -XX:-UseAdapativeSizePolicy -XX:SurvivorRatio=6)

这次的测试时间是上次的两倍,而垃圾的平均创建速率和之前基本一致(30.2MB/s,之前是30.5MB/s)。然而,整个过程只有两次老年代(Full)GC暂停,25小时左右才发生一次。这是因为老年代垃圾死亡速率(所谓的promation rate)从137kB/s减小到了6kB/s,老年代的垃圾回收只占整体的0.02%。同时新生代GC的暂停持续时间仅仅从平均48ms增加到57ms,两次暂停的间隔从6s增长到10s。总之,关闭了自适应大小调整,合理地优化堆内存大小,使GC暂停占总时间的比例从0.95%减小到0.59%,这是一个非常棒的结果。

优化后,使用ParNew算法作为默认ParallelGC的替代,也能得到相似的结果。这个算法是为了与CMS算法兼容而开发的,可以通过JVM参数来配置-XX:+UseParNewGC。关于CMS下面会提到。这个算法不使用自适应大小策略,可以运行在固定Survivor大小的空间上。因此,即使使用默认的配置SurvivorRatio=8,也比ParallelGC拥有更高的服务器利用率。

避免老年代GC的长时间暂停

上述结果的最后一个问题就是,老年代GC的长时间暂停平均为8s左右。通过适当的优化,老年代GC暂停已经很少了,但是一旦触发,对用户来说还是很烦人的。因为在暂停期间,JVM不能执行工作线程。在我们的例子中,8s的长度是由低速老旧的测试机导致的,在现代硬件上速度能快3倍左右。另一方面,现在的应用一般使用1G以上的堆内存,可以容纳更多的对象。当前的网络应用使用的堆内存能达到64GB,(至少)需要一半的内存来保存存活的对象。在这种情况下,8s对老年代暂停来说是很短的。这些应用中的老年代GC可以很随意地就接近1分钟,对于交互式网络应用来说是绝对不能接受的。

缓解这个问题的一个选择就是采用并行的方式处理老年代GC。默认情况下,在Java 6中,ParallelGC和ParNew GC算法使用多个GC线程来处理新生代GC,而老年代GC是单线程的。以ParallelGC回收器为例,可以在使用时添加以下参数:

-XX:+UseParallelOldGC
로그인 후 복사

从Java 7开始,这个选项和-XX:+UseParallelGC默认被激活。但是,即使你的系统是4核或8核,也不要期望性能可以提高2倍以上。通常的结果会比2被小一些。在某些例子中,比如上述例子中的8s,这种提高还是比较有效的。但在很多极端的例子中,这还远远不够。解决方法是使用低延迟GC算法。

下篇中会讨论CMS(The Concurrent Mark and Sweep Collector)、幽灵般的碎片、G1(Garbage First)垃圾收集器和垃圾收集器的量化比较,最后给出总结。

위 내용은 미션 크리티컬 Java 애플리케이션을 위한 가비지 수집 최적화에 대한 자세한 설명(1부)의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.

핫 AI 도구

Undresser.AI Undress

Undresser.AI Undress

사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover

AI Clothes Remover

사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool

Undress AI Tool

무료로 이미지를 벗다

Clothoff.io

Clothoff.io

AI 옷 제거제

AI Hentai Generator

AI Hentai Generator

AI Hentai를 무료로 생성하십시오.

인기 기사

R.E.P.O. 에너지 결정과 그들이하는 일 (노란색 크리스탈)
3 몇 주 전 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. 최고의 그래픽 설정
3 몇 주 전 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. 아무도들을 수없는 경우 오디오를 수정하는 방법
3 몇 주 전 By 尊渡假赌尊渡假赌尊渡假赌
WWE 2K25 : Myrise에서 모든 것을 잠금 해제하는 방법
4 몇 주 전 By 尊渡假赌尊渡假赌尊渡假赌

뜨거운 도구

메모장++7.3.1

메모장++7.3.1

사용하기 쉬운 무료 코드 편집기

SublimeText3 중국어 버전

SublimeText3 중국어 버전

중국어 버전, 사용하기 매우 쉽습니다.

스튜디오 13.0.1 보내기

스튜디오 13.0.1 보내기

강력한 PHP 통합 개발 환경

드림위버 CS6

드림위버 CS6

시각적 웹 개발 도구

SublimeText3 Mac 버전

SublimeText3 Mac 버전

신 수준의 코드 편집 소프트웨어(SublimeText3)

자바의 완전수 자바의 완전수 Aug 30, 2024 pm 04:28 PM

Java의 완전수 가이드. 여기서는 정의, Java에서 완전 숫자를 확인하는 방법, 코드 구현 예제에 대해 논의합니다.

Java의 난수 생성기 Java의 난수 생성기 Aug 30, 2024 pm 04:27 PM

Java의 난수 생성기 안내. 여기서는 예제를 통해 Java의 함수와 예제를 통해 두 가지 다른 생성기에 대해 설명합니다.

자바의 웨카 자바의 웨카 Aug 30, 2024 pm 04:28 PM

Java의 Weka 가이드. 여기에서는 소개, weka java 사용 방법, 플랫폼 유형 및 장점을 예제와 함께 설명합니다.

Java의 스미스 번호 Java의 스미스 번호 Aug 30, 2024 pm 04:28 PM

Java의 Smith Number 가이드. 여기서는 정의, Java에서 스미스 번호를 확인하는 방법에 대해 논의합니다. 코드 구현의 예.

Java Spring 인터뷰 질문 Java Spring 인터뷰 질문 Aug 30, 2024 pm 04:29 PM

이 기사에서는 가장 많이 묻는 Java Spring 면접 질문과 자세한 답변을 보관했습니다. 그래야 면접에 합격할 수 있습니다.

Java 8 Stream foreach에서 나누거나 돌아 오시겠습니까? Java 8 Stream foreach에서 나누거나 돌아 오시겠습니까? Feb 07, 2025 pm 12:09 PM

Java 8은 스트림 API를 소개하여 데이터 컬렉션을 처리하는 강력하고 표현적인 방법을 제공합니다. 그러나 스트림을 사용할 때 일반적인 질문은 다음과 같은 것입니다. 기존 루프는 조기 중단 또는 반환을 허용하지만 스트림의 Foreach 메소드는이 방법을 직접 지원하지 않습니다. 이 기사는 이유를 설명하고 스트림 처리 시스템에서 조기 종료를 구현하기위한 대체 방법을 탐색합니다. 추가 읽기 : Java Stream API 개선 스트림 foreach를 이해하십시오 Foreach 메소드는 스트림의 각 요소에서 하나의 작업을 수행하는 터미널 작동입니다. 디자인 의도입니다

Java의 날짜까지의 타임스탬프 Java의 날짜까지의 타임스탬프 Aug 30, 2024 pm 04:28 PM

Java의 TimeStamp to Date 안내. 여기서는 소개와 예제와 함께 Java에서 타임스탬프를 날짜로 변환하는 방법에 대해서도 설명합니다.

미래를 창조하세요: 완전 초보자를 위한 Java 프로그래밍 미래를 창조하세요: 완전 초보자를 위한 Java 프로그래밍 Oct 13, 2024 pm 01:32 PM

Java는 초보자와 숙련된 개발자 모두가 배울 수 있는 인기 있는 프로그래밍 언어입니다. 이 튜토리얼은 기본 개념부터 시작하여 고급 주제를 통해 진행됩니다. Java Development Kit를 설치한 후 간단한 "Hello, World!" 프로그램을 작성하여 프로그래밍을 연습할 수 있습니다. 코드를 이해한 후 명령 프롬프트를 사용하여 프로그램을 컴파일하고 실행하면 "Hello, World!"가 콘솔에 출력됩니다. Java를 배우면 프로그래밍 여정이 시작되고, 숙달이 깊어짐에 따라 더 복잡한 애플리케이션을 만들 수 있습니다.

See all articles