質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

3回答

1560閲覧

配列のサイズが大きいC++プログラムを実行するとパソコンがクラッシュする

kabotya3

総合スコア32

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

3クリップ

投稿2022/08/28 17:11

編集2022/08/29 05:08

前提

該当のソースコードにあるようなC++プログラムを実行すると、パソコン自体がクラッシュしてしまいます。理由自体はある程度わかっていて、宣言した配列のサイズが大きすぎるからだろうと思われます。
ただプログラムがエラーを出して終了するなら良いとしても、パソコン自体がクラッシュしたのは今までにないことなのでその原因を知りたいです。よろしくお願いします。

確認したいこと

お聞きしたい点は以下の4つです。

  1. 原因はなんだろうか?
  2. あるプログラムを実行しただけでパソコンがクラッシュして、再起動してしまうのは正常と言えるか?
  3. もし正常なら、C++プログラムは常にそういったことに留意して書かれているのだろうか?(配列外参照などの話ではなくて、プログラム次第でコンピュターがクラッシュするかもしれないという点)
  4. これは私の環境特有の問題なのか?

私のOSの理解だとプログラムが実行される時に必要なリソースを渡し、それ以外の領域にはプログラムはアクセスできないようにしているはずで、プログラムの実行が失敗してもパソコン自体のクラッシュは起こりえないのではと考えていました。

補足

該当のプログラムを実際に動かそうしているわけではありません。ただ最初誤って該当のプログラム(主要箇所を抽出したものなので実際はもう少し書いてあった)を実行したところ、いきなりクラッシュから再起動し始めて疑問が湧いたということです。というわけで、知りたいことは「該当のプログラムを動かす方法」ではなく、「クラッシュした理由」ということになります。

発生している問題・エラーメッセージ

該当のソースコードをコンパイルし実行すると、5秒程度画面が固まり、操作が効かなくなります。その後画面が暗転し数秒経って再起動が始まります。

該当のソースコード

C++

1#include <bits/stdc++.h> 2using namespace std; 3 4using ll = long long; 5 6constexpr ll sz = 101010; // sz ~ 10^5 7ll table[sz][sz]; 8 9int main() { 10 ll n,W; 11 cin >> n >> W; 12 cout << n << "\n"; 13 14 15 return 0; 16}

試したこと

  1. 該当のソースコードを10回程度実行して試してみて、全てにおいて上記の現象が起こったので偶然が重なって起きたクラッシュではないと思われます。
  2. またVSCodeとFinder以外のアプリを立ち上げずに実行しても同様の現象が確認されました。
  3. コードでszを100にした場合はちゃんと動作し、クラッシュもしませんでした。

補足情報

実行環境
C++17.
コンパイラ:Apple clang version 13.1.6 (clang-1316.0.21.2.3)
MacBook Pro (M1, 2020) メモリ16GB, SSD 500GB
macOS: Monterey バージョン12.3.1

本来clangにはない<bits/stdc++.h>をincludeしてますが、これは拾ってきたbits/stdc++.hをincludeフォルダに入れている形で解決しています。

追記

  • VSCodeで実行していると書きましたが、VSCodeの統合ターミナルよりコマンドで実行しております。
  • 普段はコンパイルオプションを-std=c++17としてコンパイルしてますが、c++11としても同様のエラーが確認できました。
  • jbpb0様のIntel Macメモリ16GBでは正常に動作する。(修正依頼参照) おそらくコンパイラは問題ではなくM1チップに関する問題?。
  • 再起動時の問題レポート冒頭は次のとおりです。
panic(cpu 4 caller 0xfffffe001768b03c): Failed to reserve GPU Carveout region in user map 0xfffffe24cbfaa808 3 @vm_map.c:13285 Debugger message: panic Memory ID: 0xff OS release type: User OS version: 21E258 Kernel version: Darwin Kernel Version 21.4.0: Fri Mar 18 00:47:26 PDT 2022; root:xnu-8020.101.4~15/RELEASE_ARM64_T8101
  • また配列サイズszを101,010から71,010に変更すると再起動は起こらず、./a.out実行時に次のエラーログが出る。コンパイルはエラーなく正常にできます。1行目でdyld_shared_cache_arm64eとあって、arm64つまりM1に関わるところだろうと思います。
dyld[1704]: dyld cache '/System/Library/dyld/dyld_shared_cache_arm64e' not loaded: syscall to map cache into shared region failed dyld[1704]: Library not loaded: /usr/lib/libc++.1.dylib Referenced from: /Users/<NAME>/Desktop/programming/kyopuro/pra/a.out Reason: tried: '/usr/lib/libc++.1.dylib' (no such file), '/usr/local/lib/libc++.1.dylib' (no such file) zsh: abort ./a.out
  • ヒープに確保するよう変えると動作した。

actorbug様より

ヒープに確保するようにしたら、挙動が変わりませんかね。

C++

1ll table[sz][sz]; 2 ↓ 3ll (*table)[sz] = (ll(*)[sz])malloc(sizeof(ll) * sz * sz);

このようにすると再起動することなく、正常終了することを確認。
jbpb0様のコードのように

C++

1for(int i=0; i<sz; i++ ){ 2 for(int j=0; j<sz; j++ ){ 3 table[i][j]=i+j; 4 } 5}

を加えて実行した。アクティビティモニタでの最大メモリ使用量は実行時に大幅に増えたものの使用済みメモリ14GB程度であった。
プロセスのswap含めた最大メモリ使用量を確認したところ、74GBとなりました。
以下のコードのようにcinの前に二重ループを起き、入力せず変化がなくなるまで待ったところ76.06GBとなりました。

C++

1int main() { 2 ll n, W; 3 for(int i = 0; i < sz; i++) { 4 for(int j = 0; j < sz; j++) { 5 table[i][j] = i + j; 6 } 7 } 8 cin >> n >> W; 9 cout << n << "\n"; 10 return 0; 11}

まとめると
jbpb0様のIntel Macでll table[sz][sz];として実行した結果と
私のM1 Macでll (*table)[sz] = (ll(*)[sz])malloc(sizeof(ll) * sz * sz);として実行した結果及びメモリ使用量がほぼ同じとなる

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

kabotya3

2022/08/29 01:33

メモリ16GB, SSD 500GBで、再起動直後のSSDの残り容量が274GBとなっております。また再起動した直後のメモリーの使用済みメモリは11.9GBとなっておりました。
jbpb0

2022/08/29 02:22

当方のmacで、質問に記載のコードをそのままコンパイルして実行したら、正常に終了しました 環境 プロセッサ名: クアッドコアIntel Core i5 メモリ: 16 GB システムのバージョン: macOS 12.5.1 (21G83) コンパイラ $ which g++ /usr/bin/g++ $ g++ --version Apple clang version 13.1.6 (clang-1316.0.21.2.5) (略) コンパイルと実行 $ g++ -std=c++11 bigm.cpp $ ./a.out 1 2 1 「stdc++.h」は、下記を使いました https://gist.github.com/frankchen0130/9ac562b55fa7e03689bca30d0e52b0e5 m1とインテルという違いがあるので、ご参考程度に
kabotya3

2022/08/29 02:23

80GBも使用するアプリなどおそらく無いはずだから、スワッピングに上限が設定してあり80GBはそれを超えたのかもしれませんね。 https://answers.microsoft.com/ja-jp/windows/forum/all/%E4%BB%AE%E6%83%B3%E3%83%A1%E3%83%A2%E3%83%AA/a15dc1c2-be5c-47c2-b824-beecf38606ab Macではこのような情報は見つかりませんでしたが、Windowsでは仮想メモリ容量の上限が存在しているようです。Macも同様であればSSDが十分残っていても、仮想メモリ容量の上限までししか読み込まれないと思われます。 相談に乗っていただきありがとうございました。
kabotya3

2022/08/29 02:28

正常終了したのですね! そちらの環境で正常に実行できたとすると、私の環境に問題があるのでしょう。メモリも同じく16GBですし。うーん
jbpb0

2022/08/29 02:36

$ ./a.out を実行する前から、アクティビティモニタでメモリー使用量を確認し続けたら、 $ ./a.out を実行した後、キーボードから 1 2 を入力するまでの間のメモリー使用量は、a.out実行前とほぼ変わりませんでした てっきり、 ll table[sz][sz]; で大きなサイズの配列が確保されて、メモリー使用量が爆増すると予想してたのですが、当方のmacでの実行では、そうはなりませんでした メモリー使用量が増えないのなら、macは落ちませんよね 質問者さんが実行してmacが落ちるコードは、質問に記載のものと相違無いのですよね? 何が違うのでしょうね? 謎です m1固有の現象?
kabotya3

2022/08/29 02:37

> m1とインテルという違いがあるので、ご参考程度に 確かにその通り搭載CPUが違いますね。CPUが違うとバージョンが近いmacOSであっても、挙動が異なってしまうのか疑問が残りますが。 実行までして頂いてありがとうございました。
kabotya3

2022/08/29 02:40 編集

> 質問者さんが実行してmacが落ちるコードは、質問に記載のものと相違無いのですよね? その通りです。最初に気づいた一回目こそ色々な処理を書いてるコードでしたが、2回目移行の検証では添付コードと同一のものを使用してます。
jbpb0

2022/08/29 02:46 編集

コンパイルオプションに違いはありませんか? 私は下記だけですが、最適化とかすると挙動が変わったりするかも g++ -std=c++11
kabotya3

2022/08/29 02:52

コンパイルコマンドはg++ -std=c++17を使用してます。
jbpb0

2022/08/29 03:00 編集

ll table[sz][sz]; で宣言するだけだと実際には領域確保されないのかな、と思って、「main()」の先頭に下記を追加して、コンパイルして実行しても、大丈夫でした table[0][0] = 10; table[sz-1][sz-1] = 20; cout << table[0][0] << "\t" << table[sz-1][sz-1] << "\n"; $ ./a.out 10 20 1 2 1 「table」に代入した数値10, 20が表示されてるので、「table」は存在してるはずです しかも、この場合でも、アクティビティモニタで確認したメモリー使用量は増えてないのです 逆にその方が不思議
kabotya3

2022/08/29 03:03

> 「table」に代入した数値10, 20が表示されてるので、「table」は存在してるはずです メモリ使用量がほぼ増えないのに、tableが存在しているとは不思議です。 配列tableをグローバル領域で宣言している理由はhttps://wikiwiki.jp/kyopro/%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0%E3%81%AE%E3%83%86%E3%82%AF%E3%83%8B%E3%83%83%E3%82%AF/%E5%A4%A7%E3%81%8D%E3%81%AA%E9%85%8D%E5%88%97%E3%82%92%E7%A2%BA%E4%BF%9D%E3%81%99%E3%82%8B%E5%A0%B4%E5%90%88%E3%81%AE%E6%B3%A8%E6%84%8F のとおりです。スタック領域ではないところに確保されるようです。 今、配列サイズを101,010から71,010に変更して実行したところ、PCは再起動せず次のようなエラーが出ました。このエラーメッセージはc++11でもc++17でも発生しました。 dyld[1704]: dyld cache '/System/Library/dyld/dyld_shared_cache_arm64e' not loaded: syscall to map cache into shared region failed dyld[1704]: Library not loaded: /usr/lib/libc++.1.dylib Referenced from: /Users/<NAME>/Desktop/programming/kyopuro/pra/a.out Reason: tried: '/usr/lib/libc++.1.dylib' (no such file), '/usr/local/lib/libc++.1.dylib' (no such file) zsh: abort ./a.out そしてやはり、101,010に戻すと再起動することが確認できました。
jbpb0

2022/08/29 03:04

g++ -std=c++17 でも、同じでした メモリー使用量は増えないし、正常に実行できる
actorbug

2022/08/29 03:06

横から失礼します。 VSCodeのメニューから「実行」→「デバッグの開始」で実行していないでしょうか。 もしそうなら、「実行」→「デバッグなしで実行」にしたら、どうなるでしょうか。
kabotya3

2022/08/29 03:08

> g++ -std=c++17 > > でも、同じでした > メモリー使用量は増えないし、正常に実行できる なるほど、私の環境でもc++11でコンパイルしたところc++17と変わらない現象(再起動とサイズ71,010のエラーログ)が確認できました。おそらくコンパイラの問題は無いように思います。 エラーログを見ると '/System/Library/dyld/dyld_shared_cache_arm64e' not loaded: とあるようにarm64 つまりM1の問題かもしれません。
kabotya3

2022/08/29 03:17 編集

actorbug様へ > VSCodeのメニューから「実行」→「デバッグの開始」で実行していないでしょうか。 > もしそうなら、「実行」→「デバッグなしで実行」にしたら、どうなるでしょうか。 VSCodeの統合ターミナルからコマンドで実行している形です。(F5キーや緑右向き三角は押さずに実行しています。) 統合ターミナルからはVSCodeのデバッグ機能は呼び出されないとは思いますが、mac標準ターミナルでもテストしてみようと思います。 以下追記 mac標準ターミナルから試してみましたが、同様の現象が確認できました。
jbpb0

2022/08/29 03:27

「main()」の先頭に下記を追加して、「table」の全要素に値を代入するようにして、コンパイルして実行しました for (int i=0; i<sz; i++) { for (int j=0; j<sz; j++) { table[i][j] = i + j; } } そうすると挙動が変わり、a.outのメモリー使用量は最大で76.02GBまで増えました (実際に使われた要素のみが存在するのかな??) それでもmacは落ちませんでした 下記の後、プロンプトが正常に表示されました $ ./a.out 1 2 1 m1固有の現象なのですかね?? よく分かりません
actorbug

2022/08/29 03:38

ヒープに確保するようにしたら、挙動が変わりませんかね。 ll table[sz][sz];  ↓ ll (*table)[sz] = (ll(*)[sz])malloc(sizeof(ll) * sz * sz);
kabotya3

2022/08/29 03:53 編集

> (実際に使われた要素のみが存在するのかな??) 結果を見るにそのような感じですね。それでもmacは落ちないとなると、jbpb0様のmacでは仮想メモリ容量に上限は無いか76GB以上なのでしょう。 m1固有の現象か、gcc周りの問題のようです。配列サイズを少しだけ小さくした時にでるエラー、 dyld cache '/System/Library/dyld/dyld_shared_cache_arm64e' not loaded: syscall to map cache into shared region failedを調べていると私のgccコマンドのインストール自体がおかしい可能性があると分かりました。 Apple Clangを使っていますが、Rをインストールした時にGNUのGCCもインストールされていました。これが原因かもしれません。g++ --versionではApple clangが表示されますが。
kabotya3

2022/08/29 03:55

actorbug様へ そのようにコードを変更したところ、正常終了しました!アドバイスありがとうございます!
jbpb0

2022/08/29 04:04 編集

> そのようにコードを変更したところ、正常終了しました でのメモリー使用量は、いくつくらいでしょうか? また、そのコードに > for (int i=0; i<sz; i++) { for (int j=0; j<sz; j++) { table[i][j] = i + j; } } を追加しても、大丈夫ですか?
kabotya3

2022/08/29 04:10

二重ループですべてtableを確認しても正常終了はしました。がメモリ使用量が14GB程度とかなり少なく、ディスク項目の書き込まれたデータは19GBでした。
jbpb0

2022/08/29 04:26 編集

> メモリ使用量が14GB程度とかなり少なく それは、実メモリー16GB中の使われてる量ですかね (アクティビティモニタの下の方の表示) プロセスのメモリー使用量は、いくつくらいでしょうか? (アクティビティモニタの上の方の表示) そちらは、swapも含めた量です
kabotya3

2022/08/29 04:14

失礼しました。今一度確認したところ、a.outプロセスのメモリ使用量は最大で74GBになりました。これはjbpb0様と近い値ですね。
jbpb0

2022/08/29 04:42 編集

「table」に必要なメモリー量は 101010*101010*8/1024/1024/1024=76.0184235871GB で、それに比べて「table」以外はわずかなので、私が確認した76.02GBは、ほぼピッタリです > a.outプロセスのメモリ使用量は最大で74GB は、それよりも(ちょっとですが)少ないですね forループは、下記の前(上)に入れましたか? cin >> n >> W; また、キーボードから数値を入力するのは、アクティビティモニタでのプロセスのメモリー使用量が増えなくなるまで十分に待ちましたか? なお、当方でactorbugさんのコメントのようにコードを変えて実行しても、76.02GBは変わりませんでした
kabotya3

2022/08/29 05:11

重ねて失礼しました。言われたとおりにコードを実行したところ76.06GBで落ち着きました。3回繰り返して変わらずこの値になりました。0.04GBずれがありますが。。。
jbpb0

2022/08/29 05:15

必要なはずの量よりも少ないのは変だなぁと思いましたが、やはりそうでしたか
kabotya3

2022/08/29 06:38

たくさん相談に乗っていただきありがとうございました。全体的に私のOSの理解が甘かったですが、追記依頼を参考にしながらコードを色々変えてアクティビティモニタを見ていると勉強になりました。ヒープ確保のやり方では動作し、ll table[sz][sz];では再起動してしまうは少し不気味ですが、「M1固有の問題」または「clangとgnu gccのインストールの問題」におかげさまで絞り込むことができました。 jbpb0さん、actorbugさん色々と協力していただいてありがとうございました。
actorbug

2022/08/30 14:12

今更ですが、C++前提なら、autoとnewを使う方が楽に書けます。 ll (*table)[sz] = (ll(*)[sz])malloc(sizeof(ll) * sz * sz);  ↓ auto table = new ll[sz][sz];
guest

回答3

0

まあ、C/C++ってのは実行時のエラーチェックは全く行ってません。
異常があるときにエラーメッセージを出して止まる、という動作を期待するなら、C/C++ は使ってはいけません。

そういうことをしっかり行ってくれる言語を使いましょう。

#そう言う言語でそういう巨大な配列を動作させることができるのかってのはべつのおはなし

投稿2022/08/28 22:58

y_waiwai

総合スコア87774

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

kabotya3

2022/08/29 01:37

回答ありがとうございます。 > 異常があるときにエラーメッセージを出して止まる、という動作を期待するなら、C/C++ は使ってはいけません。 配列外参照などはsegmentation faultを出して止まってくれるので、今回のような事例では止まってくれないのか?と疑問に思い質問させていただいた次第です。止まってくれないこともあるのですね。 これからはより注意してC/C++を使っていきたいと思います。
y_waiwai

2022/08/29 02:37

セグメンテーションフォールトは、あくまで不正アクセスを行った結果、OSに捕捉されて出るもんです たまたま有効なメモリエリアに不正アクセスしてもそれは出ません なので、きちんと動いていて正常な結果が出ているとしても不正アクセスがないと言う保証はありません
guest

0

ベストアンサー

原因はなんだろうか?

異常なパラメータを持ってOSを呼び出したこと、そしてOS側のガードが不十分だったこと、でしょう。

あるプログラムを実行しただけでパソコンがクラッシュして、再起動してしまうのは正常と言えるか?

言えません。意図せず再起動するのが「正常」なわけはありません。
「こんなところにアクセスしようとするなんてもしかしてウイルス? じゃあ緊急でシャットダウンしよう」という設計思想もないとは言えませんが、それは家庭用機器向けの発想ではないと思います。

もし正常なら、C++プログラムは常にそういったことに留意して書かれているのだろうか?(配列外参照などの話ではなくて、プログラム次第でコンピュターがクラッシュするかもしれないという点)

本件が正常か異常かにかかわらず、C/C++は「安全装置」がほとんどないので、プログラムは常にそういったこと(環境に対し適切なものであるように)に留意してかかれなければいけません。そもそも異常な操作をしてはいけないわけで、異常な操作を要求してアプリケーションの動作に異常が起こったとしてもそれは「プログラマの責任だ」と言い切るのがC/C++です。
なお、アプリケーションからの異常な要求に対してOSが適切に対処できるかどうかはOS側の話ですから、切り離して考えましょう。

これは私の環境特有の問題なのか?

M1Macを持っていないので追試できません。

投稿2022/08/28 22:52

thkana

総合スコア7639

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

kabotya3

2022/08/29 01:46

詳細なご回答ありがとうございました。 私のC/C++の理解とOSの理解が不十分でしたね。C/C++の言語側あるいはOSでsegmentation fault等のように何らかの安全機構があるのではと過信しておりました。 > 言えません。意図せず再起動するのが「正常」なわけはありません 私の「正常」という言葉遣いが悪かったのですが言いたかったことは、「今回のような悪いC++のコードを書いた時にコンピュータが再起動してしまうのは、十分起こりうることなのだろうか」ということでした。解答から考えるに十分起こりうるようですね。 改めて回答ありがとうございました。
thkana

2022/08/29 12:43

> 再起動してしまうのは、十分起こりうることなのだろうか 「十分」ってのがとても困る言葉なのですが。 起こっていい話ではないけど、OSを作ったのが神ならぬ人の身だから完璧でないのは仕方ない。実際に目の前で再起動が起こっているわけだし、否定のしようもない。そういうこともあるとあきらめられる、という感じでしょうか。
guest

0

szが 10^5 ですから、ll table[sz][sz];の要素数が 10^10 個、llのサイズが 8byte なので、必要なメモリ量は 8 x 10^10 byte、つまり 80GB となります。
おそらく原因は 80GB ものメモリを OS に要求したことですが、それで OS ごと落ちるのが妥当かはわかりません。

投稿2022/08/28 21:08

actorbug

総合スコア2224

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

kabotya3

2022/08/29 01:48

なるほど、実際に要求するメモリ量を計算してみると80GBにもなるのですね。実行環境は16GBメモリでしたので、80GBも要求したら確かにおかしいです。 回答ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問