CreateThread関数を使用して、スレッドを立ち上げる際に、第二引数でスタックサイズを指定した場合、その指定したスタックサイズをOSが変更(最適化?)してプログラムが動くということはあるのでしょうか?
例)
CreateThreadでスタックサイズ「4000」を指定
ただ、実際にそのスレッドのスタックサイズは「5000」だった
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
スタックサイズの確認はどのようにされたのでしょう?
ありがとうございます。
実際にスタックサイズを確認したわけではありませんが、そのスレッドで使用している関数で宣言している自動変数のサイズを確認したところ、CreateThreadで指定したスタックサイズよりも大きくなっていることが確認できました。

回答2件
0
ベストアンサー
あります。CreateThreadの説明にあるとおりスタックのサイズはメモリのページサイズの倍数に丸められるので指定したサイズにはならないです。
あとこれはあくまで初期サイズなので足りなくなったら自動的に拡大します。
投稿2016/08/08 10:17
総合スコア2850
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
回答ありがとうございます。
>あくまで初期サイズなので足りなくなったら自動的に拡大します。
つまり、CreateThreadでスタックサイズを指定したとしても、それは意味が無いということでしょうか?
初歩的な質問で申し訳ありません。
いえ、この値は最初の確保するサイズを指定するのと同時に既定の最大サイズを増やす役割もあります。
Windowsではデフォルト(最小)で各スタックに1MBの仮想領域が割り当てられます。
ですので、CreateThreadで指定したサイズを超えても1MBまではOSが自動的に物理メモリの割り当てを拡大してくれますがそれ以上はどうやっても増えません。スタックオーバーフロー例外が発生してプログラムが終了します。
1MBよりも大きなスタックが必要な場合、あらかじめ大きな値を設定することでWindowsは割り当てる仮想領域を増やしてくれます。
CreateThreadの説明に
> また、既定のスタックサイズを減らすことにより、さらに多くのスレッドを作成することもできます。
とありますが少なくともWindows10 Update2では1MB以下を指定しても1MB確保されたのでこれは嘘だと思います。メモリが小さかった昔は意味があってそうなってたかもしれませんが。
ちなみに、デフォルト1MBと書きましたがこの値はOSの規定値ではなくて実際にはプログラムの情報に含まれていてVSだとリンクの設定で変更できます。
最小はやはり1MBのようですが。

退会済みユーザー
2016/08/19 13:17
横から失礼します。スタックが足りなくなったら自動的に拡大する、というのは初めて聞きましたが、どのようなときに拡大されますか?
関数をコールする際にスタックエリアが確保された後は、その関数を処理が抜けるまではスタックサイズは変更できないように思うのですが・・・
また、仮想領域とはなんでしょうか? スタックエリアとはどのような関係があるのでしょうか?
仮想記憶の一部の領域って意味で仮想領域と書きました。「仮想アドレス空間」の方が正しいのかな?
スレッドが作成されたときプロセスの仮想記憶の一部をスタック領域として1MBなら1MB固定で割り当てられます。このサイズを変更する方法はありませんがWindowsは最低1MB割り当てるようです。この領域分使用可能なのでCreateThreadで100KB指定しても実際は1MBありますから、スレッドからしたら拡大しているように見えます。
物理メモリも割り当て分まとめて確保されるわけではなくスレッドが必要としたときに順次確保されていきます。
関数コールのスタックエリアは↑のスタック領域のうちその関数で使用している一部分の話になります。
関数の処理の途中でスタックエリアのサイズを変更できないこともないですよ。C言語でも(多くの実装では)スタックポインタをずらすalloca関数があるくらいですから。小さくなることはあまり実用性がないので普通ないですがアセンブラで書けば不可能ではないです。辻褄が合えばプログラムは動くので。

退会済みユーザー
2016/08/20 11:37 編集
僕は使ったことがないのですが、allocaはスタックからメモリを確保するのであって、スタックのサイズを変更するのではないように思うのですが違いますか?(違いますね。下記追記参照)
勘違いしていることがありました。
ちょっと分かり難かったのは、スレッドがスタックとして使用できる全メモリ領域と、関数コール時に割り当てられる量の2種類があって、明確に区別する用語がないからかも知れません。前者をスタック予約領域、後者を単にスタックと言えばいいのでしょうかね?
少なくとも僕は勘違いしてしまいました。
スタック予約領域の使用済エリアが仮想エリアに待避されることがある、というのはまだ理解できますが、アクティブなスタックが仮想エリアに待避される状況が僕にはちょっと理解できなかったのです。理論的にはあり得るのかも知れませんが。
追記:
ここまで書いてきて更なる勘違い?に気が付きました。関数コール時にその関数コールのために確保されるスタックのサイズに上限があるのかと思っていたのですが、どうもそういったサイズを指定するところが何処にもなさそうなので、そういうサイズはないと言うことでしょうか。つまり、上記のスレッドに割り当てられるスタック予約領域の空きエリアを超えない範囲であれば、1つの関数が確保できるスタックに上限は無いということです。
上記allocaはそのあると思っていた最大サイズを変更できない、と思っていたのです。
多分以下が混じっているんだと思います
1. OSが割り当てるスタックの領域
スタックとして使用可能な空間、増減不可
2. 物理メモリが割り当てれている領域
実際にデータを読み書きできる領域、OSが必要なら増やす
1のうち実際に使用されている部分
3. 関数が呼び出されたときに確保されるスタック領域
自動変数などとして使用、allocaで増やせる
2の領域のうち、関数が使用する部分
今回の質問は1, 2の話で、cafelasmさんは3の話をされているようです。
確かに用語が混じってしまいますね、、、
> アクティブなスタックが仮想エリアに待避される状況が僕にはちょっと理解できなかったのです
この話は今回は特にしていないです。多分無いと思いますが
> つまり、上記のスレッドに割り当てられるスタック予約領域の空きエリアを超えない
> 範囲であれば、1つの関数が確保できるスタックに上限は無いということです。
はい、それであっていると思います。
関数が追加でメモリを必要になったらallocaでスタックに確保可能で最大サイズは現在のスタックポインタの位置から1のスレッドに割り当てられた領域の先頭までになります。

退会済みユーザー
2016/08/21 00:08
toki_td さん、お手数おかけしました。まとめていただいてありがとうございます。

あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。