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.

在编译失败之前,所有用户进程都使用了大约 17% 的 RAM。 (发生故障后,用户 RAM 使用量下降至 2%。)这与其他 RAM 使用量数字一致。 (1.2GB /8.0GB ~= 15%)

swap -l报告说交换完全未使用。

其他一些细节:

我们使用 g++ 6.1.0 进行构建,编译为 64 位。无论我们是否将 -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. 您可以尝试摆弄 GCC 的模板和 constexpr 递归深度限制(-ftemplate-depth-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。编译继续进行,我没有再看到虚拟机错误。

我从来没能让它转储核心,所以我实际上不知道虚拟内存、gmake、g++ 或 as 耗尽了什么。它只是不会因该错误而转储核心。我也不知道这个错误到底是什么,但它现在似乎正在发挥作用。

相关内容