Linux/IA32のmallocは一度に2GB弱まで。2GB「弱」というのは、2GBは取れないからだ。2GB制限の理由はずいぶん前にも見たことがあるこのへん(sse.co.jp)を参照のこと。これはファイルサイズの2GB制限と違って時代錯誤的なことではなく、現実に起きて納得の現象だ。そんな制限を承服するかどうかは考え方次第だ。
ではmallocではなくstaticな配列なら2GB以上取れるのか? 同じくらいのサイズまでしか取れないのです。
char mem[1024*1024*1024*2]; int main(int argc, char **argv){}
gcc曰く、「警告: 式の整数がオーバーフローしました」「配列 `mem’ の大きさが負です」…そうかintだから駄目なのか、と思ってunsignedにキャストすると正しい警告が出る。曰く、「配列 `mem’ の大きさが大きすぎます」「`mem’ の領域サイズがわかりません」。
しかしgccが配列のサイズで文句を言うのは気に食わん!
1GBで配列を取ってコンパイルし、アセンブラコードを直して
.comm mem,1073741824,32 .section .note.GNU-stack,"",@progbits ↓ .comm mem,1073741824*2,32 .section .note.GNU-stack,"",@progbits
これでコンパイル、リンクは成功する。で、できたバイナリを実行するとsegmentation fault。デバッガからも起動できない…そんなのはあたりまえだ(笑)。
じゃmmap(2)は? /dev/zeroへのmmap(2)を使えばメモリを確保できる。やはりこれも2GB制限があるのだ。MAP_FAILEDが返ってきて、Cannot allocate memoryと言われる。
スタックの場合は実はアセンブラコードを直すと2GBを越えられる。どっかでオーバーフローしてマイナスになっちゃってるのかもしれないし、たぶん動作はしないだろう。ただ、確保する(したつもり)だけでは落ちない。
…我ながら意味のないことばかりやってるな。