Java 프로세스에서 메모리를 소비하는 것은 무엇입니까?


20

중간 정도의 부하에서 Java 프로세스의 메모리 사용량을 조사하려고합니다.

  PID   USER    PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND
  12663 test    20   0 8378m 6.0g 4492 S   43  8.4 162:29.95 java

보시다시피 6Gb의 상주 메모리가 있습니다. 이제 흥미로운 부분은 다음과 같습니다. 프로세스는 다음 매개 변수로 실행됩니다.

  • -Xmx2048m
  • -Xms2048m
  • -XX : NewSize = 512m
  • -XX : MaxDirectMemorySize = 256m
  • ... GC와 다른 것들을위한 다른 것들

이러한 설정과 실제 메모리 사용량을 살펴보면이 프로세스에서 사용할 것으로 예상되는 것과 실제로 사용하는 것의 차이를 발견하게됩니다.

일반적으로 메모리 덤프는 힙 덤프를 분석하여 해결되지만이 경우 메모리는 힙 외부 어딘가에 사용됩니다.

질문 : 메모리 사용량이 많은 이유를 찾고 시도하는 단계는 무엇입니까? 해당 프로세스에서 메모리를 사용하는 것을 식별하는 데 도움이되는 도구는 무엇입니까?

편집 0

아직 공간이 충분하기 때문에 힙 관련 문제 인 것처럼 보이지 않습니다.

jmap -heap 12663

결과 (공간 절약을 위해 편집)

Heap Configuration:
MinHeapFreeRatio = 40
MaxHeapFreeRatio = 70
MaxHeapSize      = 2147483648 (2048.0MB)
NewSize          = 536870912 (512.0MB)
MaxNewSize       = 536870912 (512.0MB)
OldSize          = 1610612736 (1536.0MB)
NewRatio         = 7
SurvivorRatio    = 8
PermSize         = 21757952 (20.75MB)
MaxPermSize      = 85983232 (82.0MB)

New Generation: 45.7% used
Eden Space: 46.3% used
From Space: 41.4% used
To Space: 0.0% used
concurrent mark-sweep generation: 63.7% used
Perm Generation: 82.5% used

편집 1

pmap을 사용하면 64Mb의 할당량이 상당히 있음을 알 수 있습니다.

pmap -x 12663 | grep rwx | sort -n -k3 | less

결과 :

... a lot more of these 64Mb chunks
00007f32b8000000       0   65508   65508 rwx--    [ anon ] <- what are these?
00007f32ac000000       0   65512   65512 rwx--    [ anon ]
00007f3268000000       0   65516   65516 rwx--    [ anon ]
00007f3324000000       0   65516   65516 rwx--    [ anon ]
00007f32c0000000       0   65520   65520 rwx--    [ anon ]
00007f3314000000       0   65528   65528 rwx--    [ anon ] 
00000000401cf000       0  241904  240980 rwx--    [ anon ] <- Direct memory ?
000000077ae00000       0 2139688 2139048 rwx--    [ anon ] <- Heap ?

그렇다면 64MB 청크가 무엇인지 알아내는 방법은 무엇입니까? 무엇을 사용하고 있습니까? 어떤 종류의 데이터가 있습니까?

감사


2
나는 정확히 같은 문제가 있습니다 ... 여기 내 질문이 있습니다. stackoverflow.com/questions/18734389/… 이것에 대한 해결책이 있습니까?
DeepNightTwo

답변:


21

이 문제는이 glibc 문제 와 관련이있을 수 있습니다 .

기본적으로 메모리를 할당하는 여러 스레드가있는 경우 glibc는 잠금 경합을 피하기 위해 할당 할 수있는 사용 가능한 경기장 수를 확장합니다. 경기장은 64MB입니다. 상한선은 코어 아레나 수의 8 배를 생성하는 것입니다. 아레나는 스레드가 이미 잠겨있는 경기장에 접근하여 시간이 지남에 따라 성장할 때 요청시 생성됩니다.

스레드를 뿌린 Java에서는 많은 경기장이 빠르게 생성 될 수 있습니다. 그리고 이러한 분야에 걸쳐 할당이 퍼지고 있습니다. 처음에 각 64Mb 경기장은 커밋되지 않은 메모리에 매핑되었지만 할당을 수행 할 때 실제 메모리를 사용하기 시작합니다.

pmap에 아래와 비슷한 목록이있을 수 있습니다. 324K + 65212K = 65536K, 560K + 64976K == 65536K, 620K + 64916K == 65536K를 확인하십시오. 즉, 최대 64Mb입니다.

00007f4394000000 324K rw --- [아논]
00007f4394051000 65212K ----- [아논]
00007f4398000000 560K rw --- [아논]
00007f439808c000 64976K ----- [아논]
00007f439c000000 620K rw --- [아논]
00007f439c09b000 64916K ----- [아논]

에 관해서 해결 방법 : 버그 당신이 경기장의 수를 제한하기 위해 설정 할 수있는 몇 가지 환경 변수를 언급,하지만 당신은의 glibc 버전 높은 정도가 필요합니다.


5
Xmx와 Xms를 같은 값으로 설정하고 웹 서비스를 시작하는 sh 스크립트에서 환경 변수 "export MALLOC_ARENA_MAX = 4"를 설정하면 우리의 경우 도움이되었습니다. 그 전에는 2 ~ 8 시간마다 OOM Killer로 인해 웹 서비스가 다시 시작되었습니다. Ubuntu 14.04의 GLIBC 버전은 2.19입니다. MALLOC_ARENA_MAX 설정이 작동하려면> ​​= 2.16
이어야하므로

이 답변과 위의 의견은 저에게 생명의 은인이었습니다. 제 경우에는 MALLOC_ARENA_MAX = 1이 필요하고 효과적이었습니다.
John Bachir

3

방법에 대한 Lamdba 프로브 ? 무엇보다도 아래 스크린 샷과 유사한 메모리 사용량 분석을 보여줄 수 있습니다.

Lambda 프로브 메모리 사용량보기

때로는 pmap -x your_java_pid도움이 될 수도 있습니다.


답변 주셔서 감사합니다. 내가 올바르게 이해한다면 Lambda Probe는 Apache Tomcat을위한 것입니까? 우리는 사용하지 않습니다 ... pmap에 관해서는 상단 게시물에 정보를 추가하겠습니다
Konstantin S.

2

JProfiler는 당신이 찾고있는 것이 될 수 있지만 무료는 아닙니다. Java 프로세스의 메모리 사용량을 조사하는 또 다른 우수하고 무료 도구는 Oracle / Sun JDK 배포에서 JDK 도구로 사용 가능한 Java VisualVM입니다. 개인적으로 문제에 대한 전체적 접근 방식 (예 : JDK + OS + 디스크 모니터링 등) – Nagios, Verax NMS 또는 OpenNMS와 같은 일부 네트워크 모니터링 시스템 사용을 권장합니다.


2
JProfiler는 여기서 도움이되지 않습니다
Asaf Mesika

2

문제는 힙 외부에 있으므로 가장 좋은 후보는 다음과 같습니다.

JNI leak  
Allocation of direct memory buffer

직접 버퍼 크기를 제한했기 때문에 JNI 누출이 가장 좋습니다.


1

jmap이라는 JDK에 포함 된 힙 메모리의 할당을 볼 수있는 편리한 도구가 있습니다.이 위에 스택 등 (Xss)도 있습니다. 다음 두 가지 jmap 명령을 실행하여 메모리 사용량에 대한 자세한 정보를 얻으십시오.

jmap -heap <PID>
jmap -permstat <PID>

더 많은 정보를 얻으려면 jconsole (JDK에도 포함)을 사용하여 프로세스에 연결할 수 있습니다. 그러나 Jconsole은 애플리케이션에서 JMX를 구성해야합니다.


귀하의 답변에 감사드립니다. 그러나 문제는 어딘가에있는 것 같습니다. 나는 jmap는 일부 정보를 반영하기 위해 상단 게시물을 업데이트합니다
콘스탄틴 S.에게

프로세스에는 몇 개의 스레드가 있습니까? 대부분의 플랫폼에서 스택 크기는 기본적으로 2MB이므로 스레드 수와 곱하십시오. 그것이 모든 "누락 된"메모리를 설명하지만 아마도 그중 일부를 설명한다면 놀랍습니다.
HampusLi

약 300 개의 스레드, pmap에서 얻은 정보는 스택 크기가 1Mb입니다. 동일한 pmap 출력에서 ​​100Kb 이상을 사용하는 스택처럼 보이지 않습니다
Konstantin S.

0

JVisualVM을 사용하십시오. 사용중인 힙 메모리, PermGen 등을 알려주는 다양한 뷰가 있습니다.

귀하의 질문에 대답하십시오. Java는 메모리를 예상 한 것과 상당히 다르게 처리합니다.

-Xms 및 -Xmx 매개 변수를 설정하면 JVM이 힙에 할당 할 메모리 양과 최대 할당량을 JVM에 알려줍니다.

총 1m의 메모리를 사용하지만 -Xms256m -Xmx2g에 전달 된 Java 애플리케이션이있는 경우 JVM은 사용 된 256m의 메모리로 자체 초기화됩니다. 그보다 적게 사용하지는 않습니다. 응용 프로그램이 1m의 메모리 만 사용하는 것은 중요하지 않습니다.

둘째로. 위의 경우 어떤 시점에서 앱이 256m 이상의 메모리를 사용하는 경우 JVM은 요청을 처리하는 데 필요한만큼의 메모리를 할당합니다. 그러나 힙 크기는 다시 최소값으로 떨어지지 않습니다 . 적어도 대부분의 상황에서는 그렇지 않습니다.

귀하의 경우 최소 및 최대 메모리를 2g로 설정하므로 JVM은 시작시 2g를 할당하고 유지 관리합니다.

Java 메모리 관리는 매우 복잡하며 메모리 사용 조정은 그 자체가 작업 일 수 있습니다. 그러나 도움이 될만한 많은 자료가 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.