链接器性能与交换空间有关吗?

43
有时候,使用一个小的C程序模拟一个占用很大静态内存块的东西是非常方便的。但我发现,在更改为Fedora 15之后,该程序编译时间变得很长,从0.1秒变成了30秒。更奇怪的是,链接器(ld)将CPU利用率提高到最大,并慢慢地开始消耗所有可用内存。经过一些尝试,我设法找到了这个新问题与我的交换文件大小之间的相关性。以下是本次讨论的一个示例程序:
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#define M 1000000
#define GIANT_SIZE (200*M)

size_t g_arr[GIANT_SIZE];

int main( int argc, char **argv){   
    int i;
    for(i = 0; i<10; i++){
        printf("This should be zero: %d\n",g_arr[i]);
    }
    exit(1);
}

该程序有一个巨大的数组,其声明的大小约为200*8MB = 1.6GB的静态内存。编译此程序需要相当长的时间。
[me@bleh]$ time gcc HugeTest.c 

real    0m12.954s
user    0m6.995s
sys 0m3.890s

[me@bleh]$

对于一个 ~13 行的 C 程序,需要 13 秒!?这不对。关键是静态内存空间的大小。只要它大于总交换空间,编译就会再次快速进行。例如,我有 5.3GB 的交换空间,所以将 GIANT_SIZE 更改为 (1000*M) 可以得到以下时间:

[me@bleh]$ time gcc HugeTest.c 

real    0m0.087s
user    0m0.026s
sys 0m0.027s

啊,这就更像样了!为了进一步证明自己(如果您正在尝试这个)交换空间确实是魔数,我尝试将可用的交换空间改为19GB并再次尝试编译1000M版本:

[me@bleh]$ ls -ali /extraswap 
5986 -rw-r--r-- 1 root root 14680064000 Jul 26 15:01 /extraswap
[me@bleh]$ sudo swapon /extraswap 
[me@bleh]$ time gcc HugeTest.c 

real    4m28.089s
user    0m0.016s
sys 0m0.010s

4.5分钟过去了,它甚至没有完成!

很明显,链接器在这里做错了什么,但我不知道如何解决这个问题,除非重写程序或者搞一些交换空间。我很想知道是否有解决方案,或者我是否碰到了某个神秘的错误。

顺便说一句,所有程序都可以正确编译和运行,与所有交换业务无关。

以下是一些可能相关的信息供参考:

[]$ ulimit -a

core file size          (blocks, -c) 0
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 0
file size               (blocks, -f) unlimited
pending signals                 (-i) 27027
max locked memory       (kbytes, -l) 64
max memory size         (kbytes, -m) unlimited
open files                      (-n) 1024
pipe size            (512 bytes, -p) 8
POSIX message queues     (bytes, -q) 819200
real-time priority              (-r) 0
stack size              (kbytes, -s) 8192
cpu time               (seconds, -t) unlimited
max user processes              (-u) 1024
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited

[]$ uname -r

2.6.40.6-0.fc15.x86_64

[]$ ld --version

GNU ld version 2.21.51.0.6-6.fc15 20110118
Copyright 2011 Free Software Foundation, Inc.
This program is free software; you may redistribute it under the terms of
the GNU General Public License version 3 or (at your option) a later version.
This program has absolutely no warranty.

[]$ gcc --version

gcc (GCC) 4.6.1 20110908 (Red Hat 4.6.1-9)
Copyright (C) 2011 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

[]$ cat /proc/meminfo 
MemTotal:        3478272 kB
MemFree:         1749388 kB
Buffers:           16680 kB
Cached:           212028 kB
SwapCached:       368056 kB
Active:           489688 kB
Inactive:         942820 kB
Active(anon):     401340 kB
Inactive(anon):   803436 kB
Active(file):      88348 kB
Inactive(file):   139384 kB
Unevictable:          32 kB
Mlocked:              32 kB
SwapTotal:      19906552 kB
SwapFree:       17505120 kB
Dirty:               172 kB
Writeback:             0 kB
AnonPages:        914972 kB
Mapped:            60916 kB
Shmem:              1008 kB
Slab:              55248 kB
SReclaimable:      26720 kB
SUnreclaim:        28528 kB
KernelStack:        3608 kB
PageTables:        63344 kB
NFS_Unstable:          0 kB
Bounce:                0 kB
WritebackTmp:          0 kB
CommitLimit:    21645688 kB
Committed_AS:   11208980 kB
VmallocTotal:   34359738367 kB
VmallocUsed:      139336 kB
VmallocChunk:   34359520516 kB
HardwareCorrupted:     0 kB
AnonHugePages:    151552 kB
HugePages_Total:       0
HugePages_Free:        0
HugePages_Rsvd:        0
HugePages_Surp:        0
Hugepagesize:       2048 kB
DirectMap4k:      730752 kB
DirectMap2M:     2807808 kB

TL;DR:当C程序的(大型)静态内存略小于可用交换空间时,链接器需要很长时间来链接程序。然而,当静态空间略微大于可用交换空间时,它的速度非常快。这是怎么回事!?

重复此问题:https://dev59.com/9G445IYBdhLWcg3wOnnW - praetorian droid
1
@praetoriandroid 很好的发现,很抱歉我之前没有看到。那个问题中的答案很好地解释了这种情况的原因,但我想指出一些更进一步的问题,即为什么链接器能够处理比可用交换空间稍大的文件如此迅速? - Rooke
@Rooke:当可用的交换空间不足时,整个对象的分配可能会失败,链接器会退回到另一种更快的方法,因为它根本不需要使用交换空间。 - caf
以下是一些可能有用的信息:我根本没有交换空间,使用800 Mb缓冲区编译上面的代码大约需要6.7秒在我的电脑上。运行程序只需动态分配相同大小的缓冲区并将其清零,大约需要0.7秒-几乎少了10倍(实际上是9.5倍)。当缓冲区大小减少一半时,两个时间都减少了一半(3.4秒对0.36秒),但比率是相同的-大约是9.5倍。 - praetorian droid
@praetoriandroid,听起来你确认了我的链接时间观察。我知道动态内存分配+清零内存在链接器缓慢时会更快。但我并不是真的对此感兴趣。我的问题是为什么链接器不能一直都很快呢? - Rooke
好吧,我没有答案。只是试图更深入地探索一下。我认为特别奇怪的是链接器所花费的时间比清零那么多的内存还要多。但最奇怪的当然是GNU的开发人员为什么没有针对这种情况进行特殊优化。 - praetorian droid
3个回答

26

我能够在Ubuntu 10.10系统(GNU ld (GNU Binutils for Ubuntu) 2.20.51-system.20100908)上重现这个问题,我认为我有你的答案。首先介绍一些方法:

在确认这在我的小型虚拟机(512MB内存,2GB交换空间)中发生后,我决定最简单的方法是跟踪gcc并查看当一切变得混乱时到底发生了什么:

~# strace -f gcc swap.c

它阐明了以下内容:

vfork()                                 = 3589
[pid  3589] execve("/usr/lib/gcc/x86_64-linux-gnu/4.4.5/collect2", ["/usr/lib/gcc/x86_64-linux-gnu/4."..., "--build-id", "--eh-frame-hdr", "-m", "elf_x86_64", "--hash-style=gnu", "-dynamic-linker", "/lib64/ld-linux-x86-64.so.2", "-o", "swap", "-z", "relro", "/usr/lib/gcc/x86_64-linux-gnu/4."..., "/usr/lib/gcc/x86_64-linux-gnu/4."..., "/usr/lib/gcc/x86_64-linux-gnu/4."..., "-L/usr/lib/gcc/x86_64-linux-gnu/"..., ...], [/* 26 vars */]) = 0

...

[pid  3589] vfork()                     = 3590

...

[pid  3590] execve("/usr/bin/ld", ["/usr/bin/ld", "--build-id", "--eh-frame-hdr", "-m", "elf_x86_64", "--hash-style=gnu", "-dynamic-linker", "/lib64/ld-linux-x86-64.so.2", "-o", "swap", "-z", "relro", "/usr/lib/gcc/x86_64-linux-gnu/4."..., "/usr/lib/gcc/x86_64-linux-gnu/4."..., "/usr/lib/gcc/x86_64-linux-gnu/4."..., "-L/usr/lib/gcc/x86_64-linux-gnu/"..., ...], [/* 27 vars */]) = 0     

...

[pid  3590] lseek(13, 4096, SEEK_SET)   = 4096
[pid  3590] read(13, ".\4@\0\0\0\0\0>\4@\0\0\0\0\0N\4@\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 4096) = 4096
[pid  3590] mmap(NULL, 1600004096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f1771931000
<system comes to screeching halt>

看起来 ld 实际上正在尝试匿名映射此数组的整个静态内存空间(或者可能是整个程序,很难确定,因为程序的其余部分很小,可能全部适合那4,096个额外的字节)。

那么这很好,但为什么在超出系统可用交换空间时它依然有效呢? 让我们执行 swapoff 并再次运行 strace -f...

[pid  3618] lseek(13, 4096, SEEK_SET)   = 4096
[pid  3618] read(13, ".\4@\0\0\0\0\0>\4@\0\0\0\0\0N\4@\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 4096) = 4096
[pid  3618] mmap(NULL, 1600004096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = -1 ENOMEM (Cannot allocate memory)
[pid  3618] brk(0x60638000)             = 0x1046000
[pid  3618] mmap(NULL, 1600135168, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = -1 ENOMEM (Cannot allocate memory)
[pid  3618] mmap(NULL, 134217728, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_NORESERVE, -1, 0) = 0x7fd011864000

...

不出所料,ld似乎与上次尝试的一样,将整个空间映射到内存中。 但是系统现在无法完成这个操作,它失败了! ld再次尝试并再次失败,然后ld做了一些意想不到的事情... 它使用更少的内存继续执行。

奇怪,我想我们最好看看ld代码。可恶,它没有明确的 mmap。这必须来自于一个普通的malloc。我们将不得不使用一些调试符号来追踪此问题。不幸的是,当我构建bin-utils 2.21.1时,问题消失了。也许在较新版本的bin-utils中已经修复了?


这正是我想知道的,谢谢!我会在周一进行一些调查,所以请原谅奖励会稍微延迟一下。确实,“使用GNU C库时,包括的malloc会自动在适当的情况下使用mmap”,这可能是2MB左右(我忘记从哪里得到这个数字了,请原谅)。http://www.gnu.org/s/hello/manual/libc/Memory_002dmapped-I_002fO.html - Rooke

1

我没有观察到这种行为(在8GB桌面上使用Debian/Sid/AMD64,gcc 4.6.2,binutils gold ld(Debian 2.22的GNU Binutils)1.11)。这是更改后的程序(使用pmap显示其内存映射)。

#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#define M 1000000
#define GIANT_SIZE (2000*M)
size_t g_arr[GIANT_SIZE];
int main( int argc, char **argv){   
  int i;
  char cmd[80];
  for(i = 0; i<10; i++){
      printf("This should be zero: %d\n",g_arr[i*1000]);
  }
  sprintf (cmd, "pmap %d", (int)getpid());
  system(cmd);
  exit(0);
}

这是它的编译:

% time gcc -v -O big.c -o big
Using built-in specs.
COLLECT_GCC=/usr/bin/gcc-4.6.real
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/4.6/lto-wrapper
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Debian 4.6.2-4' --with-bugurl=file:///usr/share/doc/gcc-4.6/README.Bugs --enable-languages=c,c++,fortran,objc,obj-c++,go --prefix=/usr --program-suffix=-4.6 --enable-shared --enable-linker-build-id --with-system-zlib --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.6 --libdir=/usr/lib --enable-nls --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --enable-plugin --enable-objc-gc --with-arch-32=i586 --with-tune=generic --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
Thread model: posix
gcc version 4.6.2 (Debian 4.6.2-4) 
COLLECT_GCC_OPTIONS='-v' '-O' '-o' 'big' '-mtune=generic' '-march=x86-64'
 /usr/lib/gcc/x86_64-linux-gnu/4.6/cc1 -quiet -v -imultilib . -imultiarch x86_64-linux-gnu big.c -quiet -dumpbase big.c -mtune=generic -march=x86-64 -auxbase big -O -version -o /tmp/ccWThBP5.s
GNU C (Debian 4.6.2-4) version 4.6.2 (x86_64-linux-gnu)
    compiled by GNU C version 4.6.2, GMP version 5.0.2, MPFR version 3.1.0, MPC version 0.9
warning: MPFR header version 3.1.0 differs from library version 3.1.0-p3.
GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
ignoring nonexistent directory "/usr/local/include/x86_64-linux-gnu"
ignoring nonexistent directory "/usr/lib/gcc/x86_64-linux-gnu/4.6/../../../../x86_64-linux-gnu/include"
#include "..." search starts here:
#include <...> search starts here:
 /usr/lib/gcc/x86_64-linux-gnu/4.6/include
 /usr/local/include
 /usr/lib/gcc/x86_64-linux-gnu/4.6/include-fixed
 /usr/include/x86_64-linux-gnu
 /usr/include
End of search list.
GNU C (Debian 4.6.2-4) version 4.6.2 (x86_64-linux-gnu)
    compiled by GNU C version 4.6.2, GMP version 5.0.2, MPFR version 3.1.0, MPC version 0.9
warning: MPFR header version 3.1.0 differs from library version 3.1.0-p3.
GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
Compiler executable checksum: 4b128876859f8f310615c7040fa3cb67
COLLECT_GCC_OPTIONS='-v' '-O' '-o' 'big' '-mtune=generic' '-march=x86-64'
 as --64 -o /tmp/ccm7905b.o /tmp/ccWThBP5.s
COMPILER_PATH=/usr/lib/gcc/x86_64-linux-gnu/4.6/:/usr/lib/gcc/x86_64-linux-gnu/4.6/:/usr/lib/gcc/x86_64-linux-gnu/:/usr/lib/gcc/x86_64-linux-gnu/4.6/:/usr/lib/gcc/x86_64-linux-gnu/
LIBRARY_PATH=/usr/lib/gcc/x86_64-linux-gnu/4.6/:/usr/lib/gcc/x86_64-linux-gnu/4.6/../../../x86_64-linux-gnu/:/usr/lib/gcc/x86_64-linux-gnu/4.6/../../../../lib/:/lib/x86_64-linux-gnu/:/lib/../lib/:/usr/lib/x86_64-linux-gnu/:/usr/lib/../lib/:/usr/lib/gcc/x86_64-linux-gnu/4.6/../../../:/lib/:/usr/lib/
COLLECT_GCC_OPTIONS='-v' '-O' '-o' 'big' '-mtune=generic' '-march=x86-64'
 /usr/lib/gcc/x86_64-linux-gnu/4.6/collect2 --build-id --no-add-needed --eh-frame-hdr -m elf_x86_64 --hash-style=both -dynamic-linker /lib64/ld-linux-x86-64.so.2 -o big /usr/lib/gcc/x86_64-linux-gnu/4.6/../../../x86_64-linux-gnu/crt1.o /usr/lib/gcc/x86_64-linux-gnu/4.6/../../../x86_64-linux-gnu/crti.o /usr/lib/gcc/x86_64-linux-gnu/4.6/crtbegin.o -L/usr/lib/gcc/x86_64-linux-gnu/4.6 -L/usr/lib/gcc/x86_64-linux-gnu/4.6/../../../x86_64-linux-gnu -L/usr/lib/gcc/x86_64-linux-gnu/4.6/../../../../lib -L/lib/x86_64-linux-gnu -L/lib/../lib -L/usr/lib/x86_64-linux-gnu -L/usr/lib/../lib -L/usr/lib/gcc/x86_64-linux-gnu/4.6/../../.. /tmp/ccm7905b.o -lgcc --as-needed -lgcc_s --no-as-needed -lc -lgcc --as-needed -lgcc_s --no-as-needed /usr/lib/gcc/x86_64-linux-gnu/4.6/crtend.o /usr/lib/gcc/x86_64-linux-gnu/4.6/../../../x86_64-linux-gnu/crtn.o
gcc -v -O big.c -o big  0.07s user 0.01s system 90% cpu 0.089 total

以及它的执行:

  % time ./big
 This should be zero: 0
 This should be zero: 0
 This should be zero: 0
 This should be zero: 0
 This should be zero: 0
 This should be zero: 0
 This should be zero: 0
 This should be zero: 0
 This should be zero: 0
 This should be zero: 0
 8835:   ./big
 0000000000400000      4K r-x--  /home/basile/tmp/big
 0000000000401000      4K rw---  /home/basile/tmp/big
 0000000000402000 15625000K rw---    [ anon ]
 00007f2d15a44000   1512K r-x--  /lib/x86_64-linux-gnu/libc-2.13.so
 00007f2d15bbe000   2048K -----  /lib/x86_64-linux-gnu/libc-2.13.so
 00007f2d15dbe000     16K r----  /lib/x86_64-linux-gnu/libc-2.13.so
 00007f2d15dc2000      4K rw---  /lib/x86_64-linux-gnu/libc-2.13.so
 00007f2d15dc3000     20K rw---    [ anon ]
 00007f2d15dc8000    124K r-x--  /lib/x86_64-linux-gnu/ld-2.13.so
 00007f2d15fb4000     12K rw---    [ anon ]
 00007f2d15fe4000     12K rw---    [ anon ]
 00007f2d15fe7000      4K r----  /lib/x86_64-linux-gnu/ld-2.13.so
 00007f2d15fe8000      4K rw---  /lib/x86_64-linux-gnu/ld-2.13.so
 00007f2d15fe9000      4K rw---    [ anon ]
 00007ffff5b5b000    132K rw---    [ stack ]
 00007ffff5bff000      4K r-x--    [ anon ]
 ffffffffff600000      4K r-x--    [ anon ]
  total         15628908K
 ./big  0.00s user 0.00s system 0% cpu 0.004 total

我相信安装一个最新的GCC(例如GCC 4.6)和一个binutils Gold链接器对于这样的程序非常重要。

我没有听到任何涉及交换的声音。


请注意,我要求基本的-O优化。 - Basile Starynkevitch
但即使没有任何优化,编译和运行仍然几乎是瞬间完成的。 - Basile Starynkevitch
感谢您的测试,Basile。请记住,我对链接器决定执行某些操作的原因比运行时特性更感兴趣。使用您设置的GIANT_SIZE(2000M)编译在我的计算机上也很顺畅。关键是尝试将数组的大小设置为刚好小于总交换*大小。还要注意我的binutils版本为2.21.51.0.6-6.fc15,其中包括所谓的gold链接器。但我不知道它是否真的被使用了。 - Rooke
Rooke,你可以在编译和链接命令gcc HugeTest.c中添加-v选项,这样gcc将打印每个子程序及其所有选项。 - osgx
我能看到Basile的链接器和我的唯一区别是选项'--hash-style=both'。在我的Fedora盒子上,它是--hash-style=gnu。我找到了一个令人满意的解释,说明了这样做的作用(请参见链接),但我怀疑这是否有任何影响。https://sites.google.com/site/avinesh/binaryincompatibilitybetweenrhel4andrhel - Rooke

1

我对我的OpenSuse 11.4进行了折磨性测试(一周后升级到12.1)

我有4GiB的内存+2GiB的交换空间,没有注意到严重的减速,系统有时可能会出现崩溃,但编译时间仍然很短。

最长的时间是6秒,当时进行了大量的交换操作。

[tester@ulises ~]$ free -m
             total       used       free     shared    buffers     cached
Mem:          3456       3426         30          0          4        249
-/+ buffers/cache:       3172        284
Swap:         2055       1382        672
[tester@ulises ~]$ time cc -Wall -O test2.c
test2.c: In function ‘main’:
test2.c:13:2: warning: format ‘%d’ expects type ‘int’, but argument 2 has type ‘size_t’

real    0m6.501s
user    0m0.101s
sys     0m0.078s
[tester@ulises ~]$ free -m
             total       used       free     shared    buffers     cached
Mem:          3456       3389         67          0          5        289
-/+ buffers/cache:       3094        362
Swap:         2055       1455        599
[tester@ulises ~]$ free -m
             total       used       free     shared    buffers     cached
Mem:          3456       3373         82          0          4        264
-/+ buffers/cache:       3104        352
Swap:         2055       1442        612
[tester@ulises ~]$ time cc -Wall -O test2.c
test2.c: In function ‘main’:
test2.c:13:2: warning: format ‘%d’ expects type ‘int’, but argument 2 has type ‘size_t’

real    0m1.122s
user    0m0.086s
sys     0m0.045s
[tester@ulises ~]$ time cc -Wall -O test2.c
test2.c: In function ‘main’:
test2.c:13:2: warning: format ‘%d’ expects type ‘int’, but argument 2 has type ‘size_t’

real    0m0.095s
user    0m0.047s
sys     0m0.032s
[tester@ulises ~]$ free -m
             total       used       free     shared    buffers     cached
Mem:          3456       3376         79          0          4        252
-/+ buffers/cache:       3119        336
Swap:         2055       1436        618
[tester@ulises ~]$ time cc -Wall -O test2.c
test2.c: In function ‘main’:
test2.c:13:2: warning: format ‘%d’ expects type ‘int’, but argument 2 has type ‘size_t’

real    0m0.641s
user    0m0.054s
sys     0m0.040s

在运行过程中,我加载和卸载了Virtualbox Box VM、Eclipse、大型PDF文件,仅使用Firefox就占用了800多MiB。我没有达到极限,否则许多应用程序将被操作系统杀死。它更喜欢杀死Firefox.. :-)

我还走向了极端,定义了:

#define M 1048576
#define GIANT_SIZE (20000*M)

即使如此,仍然没有显著的变化。

[tester@ulises ~]$ time cc -Wall -O test2.c
test2.c:7:14: warning: integer overflow in expression
test2.c:7:8: error: size of array ‘g_arr’ is negative
test2.c:7:1: warning: variably modified ‘g_arr’ at file scope
test2.c: In function ‘main’:
test2.c:13:2: warning: format ‘%d’ expects typeint’, but argument 2 has type ‘size_t’

real    0m0.661s
user    0m0.043s
sys     0m0.031s

编辑: 我在一台分配了512MiB RAM和1.5GiB交换空间的虚拟机上重新测试了Fedora16,结果与之前类似,只是在我的“最大压力版本”中出现了一个错误消息,其中20000兆字节被分配给了数组。错误显示数组大小为负数。

[ricardo@localhost ~]$ time gcc -Wall test2.c 
test2.c:7:14: warning: integer overflow in expression [-Woverflow]
test2.c:7:8: error: size of array ‘g_arr’ is negative
test2.c:7:1: warning: variably modified ‘g_arr’ at file scope [enabled by default]
test2.c: In function ‘main’:
test2.c:13:2: warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘size_t’ [-Wformat]

real    0m1.053s
user    0m0.050s
sys     0m0.137s

在opensuse 12.1虚拟机中也出现了同样的响应问题。Fedora 16的安装速度非常慢,而且内存占用很高(在安装过程中,我不得不使用800MiB,而OpenSuse只需要512 MiB),我无法在Fedora上使用swapoff,因为它使用了大量的交换空间。在OpenSuse 12.1和Fedora上都没有遇到过迟缓或内存问题。两者都使用相同版本的内核、gcc等,并且都使用KDE作为桌面环境。
我无法重现你的问题,可能是与gcc有关的问题。尝试下载旧版本(如4.5)并查看会发生什么。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接