11

私は小さなソフトウェア エンジンを設計しており、多数のセットを迅速に反復するためにスタックを高価に使用したいと考えています。しかし、スタックはヒープほど大きなメモリストアではないため、これは悪い考えかもしれないと思いました。しかし、私はスタックの速度と、動的割り当てのコーディング手法の欠如に惹かれています。

特定のプラットフォームでスタックをどこまでプッシュできるかを調べる方法はありますか? 私は主にモバイル デバイスを調べていますが、この問題はどのプラットフォームでも発生する可能性があります。

4

5 に答える 5

7

*nix では、以下を使用しますgetrlimit

   RLIMIT_STACK
          The maximum size of the process stack, in bytes.  Upon
          reaching this limit, a SIGSEGV signal is generated.  To handle
          this signal, a process must employ an alternate signal stack
          (sigaltstack(2)).

Windows では、次を使用しますVirtualQuery

最初の呼び出しでは、スタック上の任意の値のアドレスを渡して、コミットされたスタック領域のベース アドレスとサイズ (バイト単位) を取得します。スタックが下向きに成長する x86 マシンでは、ベース アドレスと VirtualQuery からサイズを引きます。これにより、スタック用に予約されたスペースのサイズが得られます (その時点でスタック サイズの制限に正確に達していないと仮定します)。 )。2 つを合計すると、スタックの合計サイズが自然に得られます。

スタック サイズは実装とホスト システムに論理的に任されているため、プラットフォームに依存しない方法はありません。組み込みの mini-SOC では、128GB RAM サーバーよりも配布するリソースが少なくなります。ただし、API 固有の呼び出しと同様に、すべての OS で特定のスレッドのスタック サイズに影響を与えることができます。

于 2013-06-22T13:01:25.450 に答える
6

可能性のある移植可能な解決策は、アロケーターを自分で作成することです。
プロセス スタックを使用する必要はありません。ヒープでシミュレートするだけです。
最初に大量のメモリを割り当て、その上にスタック アロケータを記述して、割り当てながら使用します。
C++ でそれを実現する方法については、Google の「Allocator Requirements」を参照してください。

「スタック アロケーター」という用語が標準的なものかどうかはわかりませんが、割り当てまたは割り当て解除が発生する場所にスタックのような制限を設ける必要があることを意味します。
あなたのアルゴリズムはこのパターンに適しているとおっしゃっていたので、簡単だと思います。

于 2013-06-22T13:28:07.943 に答える
2

標準 C++ では、間違いなくそうではありません。ポータブルな方法では、おそらくそうではありません。特定の OS では、時々。他に何もない場合は、独自の実行可能サイズを開き、実行可能ファイルのヘッダーを調べて、スタックサイズを確認できます。[もちろん、次の問題は「このコードの前にどれだけのスタックが使用されたか」であり、これを判断するのは難しい場合があります]。

別のスレッドでコードを実行する場合、(低レベルの) スレッド インターフェイスの多くで、Posix スレッドpthread_set_stacksizeや MSなどのスタック (またはスタックサイズ) を指定できます_beginthread。繰り返しますが、実際のスレッド コードに到達する前にどれだけのスペースが使用されたかは正確にはわかりませんが、おそらくそれほど多くはありません。

もちろん、組み込みシステム (携帯電話など) では、スタックサイズは通常非常に小さく、4K、12K、または 64KB が通常です。システムによっては、それよりもはるかに小さい場合もあります。

別の潜在的な問題は、スタック上で実際に使用されているスペースの量を実際に知ることができないことです.コンパイルされたシステムで事後に測定できint array[25];ます.少なくともアップ25 * sizeof(int)- ただし、パディングがある可能性があり、コンパイラはレジスタをスタックに保存します。

後付けとして編集:2つのコードパスを持つことにはあまりメリットがありません:

 if (enough_stack_space_for_something)
      use_stack_based_algorithm();
 else
      use_heap_based_algorithm();

これにより、かなりの量の余分なオーバーヘッドが追加されます。一般に、組み込み/モバイル システムでは、コードを増やすことは適切な計画ではありません。

Edit2:また、メモリの割り当てがランタイムの主要な部分である場合、おそらくその理由を調べます。たとえば、オブジェクトのブロック作成が役立ちますか?

于 2013-06-22T13:01:11.380 に答える
2

これを行うための移植可能な方法がない理由について既に与えられた回答を拡張すると、実際のスタックの概念全体が標準の一部ではありません。関数呼び出しレコード (内部的にリンクされたリストなどである可能性があります) 以外にスタックをまったく使用しない C または C++ ランタイムを作成できます。

スタックは、特定のマシン/OS/コンパイラの実装の詳細です。したがって、スタック メトリックにアクセスする手法は、マシン/OS/コンパイラに固有のものになります。

特定の質問に対する実際の回答ではありませんが(Nielsはそれを非常によくカバーしています)、問題のドメインへのアドバイスとして、ヒープに大量のメモリを割り当てるだけです。利便性以外に、「実際の」スタックが異なる理由はありません。高度に再帰的な (非末尾再帰的な) アルゴリズムでは、事実上無制限の「スタック」を確保するために、多くの場合これを行う必要があります。ホスト アプリケーションをクラッシュさせるのではなく、ランタイム エラー/例外を確実に発生させたいスクリプト言語も、これを行うことがよくあります。物事を効率的に行うには、「分割スタック」を実装するか (std::dequeが提供するように)、必要に応じて十分な大きさのスタックを事前に割り当てることができます。

于 2013-06-22T19:04:19.067 に答える
1

言語内からそれを行う標準的な方法はありません。クエリが可能な文書化された拡張機能についても知りません。

ただし、一部のコンパイラには、スタック サイズを設定するオプションがあります。また、プラットフォームは、プロセスを起動するときに何をするかを指定したり、新しいスレッドのスタックサイズを設定したり、既存のスレッドを操作したりする方法を提供したりできます。

小規模なプラットフォームの場合、通常、メモリ サイズ全体を把握し、すべてのデータ セグメントを一方の端に配置し、ヒープのサイズを設定 (0 の場合もあります) し、残りはスタックとして反対側からアプローチします。

于 2013-06-22T13:00:43.110 に答える