Solaris 10: 가상 메모리가 소진되었습니다.

Solaris 10: 가상 메모리가 소진되었습니다.

우리 팀은 모두 Linux 또는 MacOS에서만 작업하는 프로그래머이지만 고객은 Solaris 10을 사용하므로 그곳에서 작동하려면 코드가 필요합니다. 그래서 우리는 테스트를 위해 오래된 SunFire V240과 임대한 Solaris 10 VM을 찾았습니다.

코드는 VM에서는 제대로 컴파일되지만 SunFire에서는 실패합니다. 우리 코드에는 빌드의 일부로 자동 생성된 거대한 C++ 파일이 있습니다. 컴파일할 수 없는 거대한 파일입니다. 다음 메시지와 함께 실패합니다.virtual memory exhausted: Not enough space

나는 그것을 알아낼 수 없다. SunFire에는 8GB의 RAM이 있으며 컴파일이 1.2GB를 조금 넘으면 가상 메모리 소모가 발생합니다. 다른 중요한 것은 실행되지 않습니다. 다음은 거의 실패에 가까운 메모리 통계입니다.

사용 prstat -s size:

SIZE (virtual memory): 1245 MB
RSS  (real memory):    1200 MB

에 따르면 echo "::memstat" | mdb -k여전히 많은 메모리를 사용할 수 있습니다.

Free (cachelist) is 46%
Free (freelist)  is 26% of total.

컴파일이 실패하기 전에 모든 사용자 프로세스는 RAM의 약 17%를 사용했습니다. (장애 발생 후 사용자 RAM 사용량은 2%로 떨어졌습니다.) 이는 다른 RAM 사용량 수치와 일치합니다. (1.2GB /8.0GB ~= 15%)

swap -l보고서에 따르면 스왑은 완전히 사용되지 않았습니다.

기타 세부정보:

우리는 64비트용으로 컴파일된 g++ 6.1.0을 사용하여 구축했습니다. -m64 플래그를 컴파일러에 전달하는지 여부에 관계없이 실패합니다.

# uname -a 
SunOS servername 5.10 Generic_147440-27 sun4u sparc SUNW,Sun-Fire-V240

VM 및 SunFire에 대한 시스템 제한은 다음과 같이 설정됩니다.

>ulimit -a
core file size          (blocks, -c) unlimited
data seg size           (kbytes, -d) unlimited
file size               (blocks, -f) unlimited
open files                      (-n) 256
pipe size            (512 bytes, -p) 10
stack size              (kbytes, -s) 8192
cpu time               (seconds, -t) unlimited
max user processes              (-u) 29995
virtual memory          (kbytes, -v) unlimited

(using su)>rctladm -l
...
process.max-address-space   syslog=off     [ lowerable deny no-signal bytes ]
process.max-file-descriptor syslog=off     [ lowerable deny count ]
process.max-core-size       syslog=off     [ lowerable deny no-signal bytes ]
process.max-stack-size      syslog=off     [ lowerable deny no-signal bytes ]
process.max-data-size       syslog=off     [ lowerable deny no-signal bytes ]
process.max-file-size       syslog=off     [ lowerable deny file-size bytes ]
process.max-cpu-time        syslog=off     [ lowerable no-deny cpu-time inf seconds ]
...

스택 크기를 "무제한"으로 설정하려고 시도했지만 눈에 띄는 차이는 없었습니다.

# df
/                  (/dev/dsk/c1t0d0s0 ):86262876 blocks  7819495 files
/devices           (/devices          ):       0 blocks        0 files
/system/contract   (ctfs              ):       0 blocks 2147483608 files
/proc              (proc              ):       0 blocks    29937 files
/etc/mnttab        (mnttab            ):       0 blocks        0 files
/etc/svc/volatile  (swap              ):14661104 blocks  1180179 files
/system/object     (objfs             ):       0 blocks 2147483465 files
/etc/dfs/sharetab  (sharefs           ):       0 blocks 2147483646 files
/platform/sun4u-us3/lib/libc_psr.so.1(/platform/sun4u-us3/lib/libc_psr/libc_psr_hwcap1.so.1):86262876 blocks  7819495 files
/platform/sun4u-us3/lib/sparcv9/libc_psr.so.1(/platform/sun4u-us3/lib/sparcv9/libc_psr/libc_psr_hwcap1.so.1):86262876 blocks  7819495 files
/dev/fd            (fd                ):       0 blocks        0 files
/tmp               (swap              ):14661104 blocks  1180179 files
/var/run           (swap              ):14661104 blocks  1180179 files
/home              (/dev/dsk/c1t1d0s0 ):110125666 blocks  8388083 files

편집 1: 16GB 스왑 파일을 설정한 후 출력 스왑:

참고: 블록 크기는 512입니다.

# swap -l
swapfile            dev    swaplo   blocks    free
/dev/dsk/c1t0d0s1   32,25  16       2106416   2106416  
/home/me/tmp/swapfile -    16       32964592  32964592

# swap -s
total: 172096k bytes allocated + 52576k reserved = 224672k used, 23875344k available 

답변1

시도해 볼만한 몇 가지 사항이 있습니다.

  1. @AndrewHenle이 옳다고 생각합니다더 많은 스왑 공간이 필요합니다..
  2. -ftemplate-depthGCC의 템플릿과 constexpr 재귀 깊이 제한( 및 constexpr -fconstexpr-depth) 을 조작해 볼 수 있습니다 . 그러나 어떤 표현이 메모리 부족을 일으키는지 이해하는 데 기껏해야 도움이 되기를 바랍니다.
  3. 몇 가지 디버깅 팁(자세한 내용은 아래 참조)

이 문서에서는 Solaris에서 스왑 공간을 늘리는 방법을 자세히 설명합니다., 그러나 언젠가는 링크가 깨질 것이므로 기사 요약은 다음과 같습니다.

# Identify the current swap volume.
$ swap -l
swapfile                 dev  swaplo   blocks   free
/dev/zvol/dsk/rpool/swap 256,1      16 1058800 1058800
# Do one of the following:
# a) Modify the existing swap volume (REQUIRES REBOOT)
    $ zfs get volsize rpool/swap
    NAME        PROPERTY  VALUE    SOURCE
    rpool/swap  volsize   517M     -

    $ zfs set volsize=2g rpool/swap

    $ zfs get volsize rpool/swap
    NAME        PROPERTY  VALUE    SOURCE
    rpool/swap  volsize   2G       -

    $ init 6
# b) Add an additional swap volume
    # Create it
    $ zfs create -V 2G rpool/swap2

    # Activate it
    $ swap -a /dev/zvol/dsk/rpool/swap2

    $ swap -l
    swapfile                  dev  swaplo   blocks   free
    /dev/zvol/dsk/rpool/swap  256,1      16 1058800 1058800
    /dev/zvol/dsk/rpool/swap2 256,3      16 4194288 4194288

    # Add an entry for the new volume in /etc/vfstab
    $ /opt/csw/gnu/grep -P '\sswap' /etc/vfstab
    /dev/zvol/dsk/rpool/swap  - - swap - no -
    /dev/zvol/dsk/rpool/swap2 - - swap - no -

문제를 진단하려면 다음을 시도해 볼 수 있습니다.

# This tells Solaris to add all available sections into coredumps &
# place coredumps in your home directory with the given pattern
$ coreadm -p ~/%t.%n.%u.%f.%p.core -P all

$ gcc ${flags} source.cc -fsyntax-only
$ gcc ${flags} source.cc -c -o source.o

찾아보거나 시도해 볼 사항:

  • 충돌할까요 -fsyntax-only?
  • 둘 다 충돌하면 거의 동일한 코어 덤프 크기가 ​​생성됩니까?
  • 코어 덤프 크기는 충돌이 발생하기 전에 프로세스가 획득한 메모리 양을 나타내야 합니다. 이를 시스템 제한과 비교해 보세요.
    • topSolaris 시스템 에서는 물리적 메모리 511G, 사용 가능한 메모리 153G, 총 스왑 공간 20G, 사용 가능한 스왑 공간 20G를 볼 수 있습니다.
    • 실행 swap -l및 비교
  • 스왑 크기를 변경한 후 동작에 눈에 띄는 변화가 있습니까?
    • 충돌이 더 빨리 발생하고 충돌하는 데 시간이 더 오래 걸립니다.
    • 코어 크기는 다양함
  • 의도적으로 더 작은 스왑 크기를 사용하거나 스왑 파티션을 완전히 제거하여 더 빨리 충돌하는지, 더 작은 코어 덤프를 생성하는지 또는 다른 방식으로 동작이 변경되는지 확인하십시오.
  • 큰 하드 드라이브를 넣고 전체 드라이브를 교환용으로 사용하십시오.

또한 다음과 같은 일부 GCC 플래그를 확인하세요.

  • -Q각 패스에 대한 컴파일 타임 함수 이름과 통계를 인쇄합니다.
  • -ftime-report배송별 시간정보
  • 다양한 -fdump-rtl*깃발
  • 다양한 단계(전처리기, 어셈블리 등)에서 출력을 가져와서 다른 동작이 나타나는지 확인하세요.

답변2

이것은 gmake 3.81의 버그인 것으로 밝혀졌습니다. make를 사용하지 않고 직접 컴파일 명령을 실행하면 더 많은 메모리를 사용할 수 있습니다. 3.80에는 알려진 버그가 있는 것 같습니다.이 같은. 이 버그는 3.81에서 수정되어야 합니다. 하지만 매우 비슷한 오류가 발생했습니다.

그래서 gmake 3.82를 사용해 보았습니다. 컴파일이 계속되고 더 이상 VM 오류가 표시되지 않습니다.

나는 코어를 덤프할 수 없었기 때문에 실제로 가상 메모리, gmake, g++ 또는 as가 부족하다는 것을 알지 못합니다. 해당 오류에 대해 코어를 덤프하지 않습니다. 이 버그가 정확히 무엇인지는 모르겠지만 현재는 작동하는 것 같습니다.

관련 정보