我有一台32GB内存的Mac服务器(雪豹)。当我尝试在Perl(v 5.10.0)中分配超过1.1GB的RAM时,出现内存不足错误。这是我使用的脚本:
#!/usr/bin/env perl
# My snow leopard MAC server runs out of memory at >1.1 billion bytes. How
# can this be when I have 32 GB of memory installed? Allocating up to 4
# billion bytes works on a Dell Win7 12GB RAM machine.
# perl -v
# This is perl, v5.10.0 built for darwin-thread-multi-2level
# (with 2 registered patches, see perl -V for more detail)
use strict;
use warnings;
my $s;
print "Trying 1.1 GB...";
$s = "a" x 1100000000; # ok
print "OK\n\n";
print "Trying 1.2 GB...";
$s = '';
$s = "a" x 1200000000; # fails
print "..OK\n";
以下是我得到的输出:
Trying 1.1 GB...OK
perl(96685) malloc: *** mmap(size=1200001024) failed (error code=12)
*** error: can't allocate region
*** set a breakpoint in malloc_error_break to debug
Out of memory!
Trying 1.2 GB...
为什么会发生这种情况?
2013年11月14日下午4:42更新
根据Kent Fredric(见下面的2个帖子),这是我的ulimits。虚拟内存默认为无限
$ ulimit -a | grep bytes data seg size (kbytes, -d) unlimited max locked memory (kbytes, -l) unlimited max memory size (kbytes, -m) unlimited pipe size (512 bytes, -p) 1 stack size (kbytes, -s) 8192 virtual memory (kbytes, -v) unlimited $ perl -E 'my $x = "a" x 1200000000; print "ok\n"' perl(23074) malloc: *** mmap(size=1200001024) failed (error code=12) *** error: can't allocate region *** set a breakpoint in malloc_error_break to debug Out of memory! $ perl -E 'my $x = "a" x 1100000000; print "ok\n"' ok
我尝试将虚拟内存设置为100亿但无济于事。
$ ulimit -v 10000000000 # 10 billion $ perl -E 'my $x = "a" x 1200000000; print "ok\n"' perl(24275) malloc: *** mmap(size=1200001024) failed (error code=12) *** error: can't allocate region *** set a breakpoint in malloc_error_break to debug Out of memory!
答案 0 :(得分:6)
您使用的是32位版本的Perl(如perl -V:ptrsize
所示),但您需要64位版本。我建议使用perlbrew
安装本地perl
。
这可以通过在安装Perl时将-Duse64bitall
传递给Configure
来实现。
这可以通过在安装Perl时将--64all
传递给perlbrew install
来实现。
(由于一些奇怪的原因,perl -V:use64bitall
说这已经完成,但显然不是。)
答案 1 :(得分:3)
似乎这可能与问题有关。这只是值得评论,但它过于复杂而不能完全无法识别
perlbrew exec --with=5.10.0 memusage perl -e '$x = q[a] x 1_000_000_000; print length($x)'
5.10.0
==========
1000000000
Memory usage summary: heap total: 2000150514, heap peak: 2000141265, stack peak: 4896
是的,对于 1 G的文字, 2 G
现在有了2G ......
perlbrew exec --with=5.10.0 memusage perl -e '$x = q[a] x 1_000_000_000; $y = q[a] x 1_000_000_000; print length($x)+length($y)'
5.10.0
==========
2000000000
Memory usage summary: heap total: 4000151605, heap peak: 4000142092, stack peak: 4896
让人惊讶。如果你有一个肯定会达到32Bit的限制。
我被宠坏了并且在5.19.5
上进行了测试,这有一个显着的改进,名为copy-on-write字符串,大大减少了内存消耗:
perlbrew exec --with=5.19.5 memusage perl -e '$x = q[a] x 1_000_000_000; $y = q[a] x 1_000_000_000; print length($x)+length($y)'
5.19.5
==========
2000000000
Memory usage summary: heap total: 2000157713, heap peak: 2000150396, stack peak: 5392
无论哪种方式,如果您使用的是除开发之外的任何版本的Perl,您需要期望它吃掉所需内存的两倍。
如果出于某种原因在32位进程的2G窗口周围存在内存限制,那么 将使用1G字符串命中。
嗯,当你做的时候
$a = $b
$a
是$b
所以当你这样做时
$a = "a" x 1_000_000_000
首先,它展开右侧,创建变量,然后将副本存储在$a
中。
您可以通过删除副本来证明这一点:
perlbrew exec --with=5.10.0 memusage perl -e 'print length(q[a] x 1_000_000_000)'
5.10.0
==========
1000000000
Memory usage summary: heap total: 1000150047, heap peak: 1000140886, stack peak: 4896
看,我所做的就是删除了中间变量,内存使用量减半!
:S
虽然因为5.19.5
仅引用原始字符串,并在写入时将其复制,但默认情况下它是有效的,因此删除中间变量的好处可以忽略不计
perlbrew exec --with=5.19.5 memusage perl -e 'print length(q[a] x 1_000_000_000)'
5.19.5
==========
1000000000
Memory usage summary: heap total: 1000154123, heap peak: 1000145146, stack peak: 5392
答案 2 :(得分:1)
它也可能是Mac对每进程内存施加的限制,以防止进程占用过多的系统内存。
我不知道这会有多有效,但我认为作为Unix的Mac有类似unix的ulimits:
有一些此类内存限制,部分摘录自/etc/security/limits.conf
- core - limits the core file size (KB)
- data - max data size (KB)
- fsize - maximum filesize (KB)
- memlock - max locked-in-memory address space (KB)
- rss - max resident set size (KB)
- stack - max stack size (KB)
- as - address space limit (KB)
bash
提供了限制和阅读这些内容的方法(有些)info bash --index-search=ulimit
例如,ulimit -a | grep bytes
在我的Linux机器上发出此信息:
data seg size (kbytes, -d) unlimited
max locked memory (kbytes, -l) 64
max memory size (kbytes, -m) unlimited
pipe size (512 bytes, -p) 8
POSIX message queues (bytes, -q) 819200
stack size (kbytes, -s) 8192
virtual memory (kbytes, -v) unlimited
我可以在范围内随意限制:
$ perl -E 'my $x = "a" x 100000000;print "ok\n"'
ok
$ ulimit -v 200000
$ perl -E 'my $x = "a" x 100000000;print "ok\n"'
Out of memory!
panic: fold_constants JMPENV_PUSH returned 2 at -e line 1.
所以ulimits
肯定是值得研究的。
答案 3 :(得分:1)
我想我明白了。我不能接受Apple在他们的文档说不同的情况下发送了32位Perl。来自'man perl':
64-BIT SUPPORT
Version 5.10.0 supports 64-bit execution (which is on by default). Version 5.8.8
only supports 32-bit execution.
然后我记得,我在我的Mac服务器上安装了Fink,而且,它是32个和64位问题。所以,我评论了
#test -r /sw/bin/init.sh && . /sw/bin/init.sh
来自我的.profile
。现在我至少可以在32 GB RAM服务器上分配14 GB RAM(是的!)
$ perl -E 'my $x = "a" x 14000000000; print "ok\n"'
ok
我尝试了16GB,但在我放弃之前它挂了5分钟。现在,diff
之间的perl -V
为32位和64位告诉故事(但为什么仍然intsize=4
?)。
$ diff perlv.32 perlv.64
16c16
< intsize=4, longsize=4, ptrsize=4, doublesize=8, byteorder=1234
---
> intsize=4, longsize=8, ptrsize=8, doublesize=8, byteorder=12345678
18c18
< ivtype='long', ivsize=4, nvtype='double', nvsize=8, Off_t='off_t', lseeksize=8
---
> ivtype='long', ivsize=8, nvtype='double', nvsize=8, Off_t='off_t', lseeksize=8
34,35c34,36
< PERL_IMPLICIT_CONTEXT PERL_MALLOC_WRAP USE_ITHREADS
< USE_LARGE_FILES USE_PERLIO USE_REENTRANT_API
---
> PERL_IMPLICIT_CONTEXT PERL_MALLOC_WRAP USE_64_BIT_ALL
> USE_64_BIT_INT USE_ITHREADS USE_LARGE_FILES
> USE_PERLIO USE_REENTRANT_API
谢谢大家的帮助,
保