4

32GB RAM を搭載した Mac サーバー (snow leopard) を使用しています。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...

なぜこれが起こっているのですか?


更新 4:42pm 11/14/13

Kent Fredric (以下の 2 つの投稿を参照) によると、これが私の ulimits です。仮想メモリのデフォルトは無制限

$ ulimit -a | grep バイト
データ セグメント サイズ (キロバイト、-d) 無制限
最大ロック メモリ (キロバイト、-l) 無制限
最大メモリ サイズ (キロバイト、-m) 無制限
パイプ サイズ (512 バイト、-p) 1
スタックサイズ (キロバイト、-s) 8192
仮想メモリ (キロバイト、-v) 無制限

$ perl -E 'my $x = "a" x 1200000000; print "ok\n"'
perl(23074) malloc: *** mmap(サイズ=1200001024) が失敗しました (エラーコード=12)
*** エラー: リージョンを割り当てられません
*** デバッグするために malloc_error_break にブレークポイントを設定します
メモリ不足です。

$ perl -E 'my $x = "a" x 1100000000; print "ok\n"'
わかった

仮想メモリを 100 億に設定しようとしましたが、役に立ちませんでした。

$ ulimit -v 10000000000 # 100 億

$ perl -E 'my $x = "a" x 1200000000; print "ok\n"'
perl(24275) malloc: *** mmap(サイズ=1200001024) が失敗しました (エラーコード=12)
*** エラー: リージョンを割り当てられません
*** デバッグするために malloc_error_break にブレークポイントを設定します
メモリ不足です。
4

4 に答える 4

6

Perl の 32 ビット ビルドを使用していますが ( で示されてperl -V:ptrsizeいます)、64 ビット ビルドが必要です。perlを使用してローカルにインストールすることをお勧めしperlbrewます。

これは、Perl のインストール時に に渡すことで実現できます-Duse64bitallConfigure

これは、Perl のインストール時に に渡すことで実現できます--64allperlbrew install

(何らかの奇妙な理由で、perl -V:use64bitallこれが行われたと言われていますが、明らかにそうではありませんでした。)

于 2013-11-14T16:44:35.157 に答える
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

うわぁ。もしあなたがそれを持っていれば、それは確かに32ビットの制限に達するでしょう.

私は甘やかされて、5.19.5でテストを行っていました。これには、メモリ消費を大幅に削減するコピーオンライト文字列という顕著な改善があります。

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 のバージョンを使用している場合は、必要なメモリを 2 倍消費することを予期する必要があります。

何らかの理由で 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
于 2013-11-15T00:31:09.203 に答える
1

私はそれを理解したと思います。Apple が 32 ビット 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 分間ハングアップしてからあきらめました。ここで、 32 ビットと 64 ビットのdiff中間perl -Vが物語っています (しかし、なぜまだなの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

助けてくれてありがとう、

ポール

于 2013-11-15T13:15:12.343 に答える