スタック領域とヒープ領域の速度

会話の中で「ヒープに比べてスタック領域の方が処理が速い」という話が出てきて,なぜそうなのかすぐにわからなかった.後で考えてみれば,ヒープ領域はアドレスから参照するしかないので,ワンステップ余計な処理が必要だな,と気がついた.けれど,そのロジックだとヒープ領域参照にかかる時間に比べて,参照してから行う処理の時間が圧倒的に大きい場合,関係なくなるなぁと思った.

そこで{スタック領域, ヒープ領域}に用意したint型変数への代入と自作クラスのインスタンスへの操作の時間を測定してみた.

実験コード

int型変数への代入
#include <iostream>
#include <ctime>
double count_stack (int n);
double count_heap (int n);

double
count_stack (int n)
{
  int a;
  std::clock_t start = std::clock();
  for (int i = 0; i < n; i++) {
    a = n; // 普通に代入
  }
  std::clock_t end = std::clock();

  return (double) (end - start) / CLOCKS_PER_SEC;
}


double
count_heap (int n)
{
  int *a = new int;
  std::clock_t start = std::clock();
  for (int i = 0; i < n; i++) {
    *a = n; // 参照して代入
  }
  std::clock_t end = std::clock();

  delete a;
  return (double) (end - start) / CLOCKS_PER_SEC;
}

int
main ()
{
  int n = 100000000;
  int LOOP_NUM = 10;
  double stack_mean = 0;
  double heap_mean = 0;

  for (int i = 0; i < LOOP_NUM; i++) {
    stack_mean += count_stack(n);
    heap_mean += count_stack(n);
  }
  std::cout << "stack: " << stack_mean / LOOP_NUM << std::endl;
  std::cout << "heap: " << heap_mean / LOOP_NUM << std::endl;

  return 0;
}
自作クラスへの操作
class Person {
  int id;
  std::string name;

public:
  Person (const int i, const char *n);
  //  ~Person ();
  void set_name (std::string str);
};

Person::Person (const int i, const char *n)
{
  id = i;
  name = n;
}

void
Person::set_name (std::string str)
{
  name = str; // こいつのコストがヒープ領域1回参照に比べてかなり大きい
}

int
main ()
{
  int n = 1000000;
  int LOOP_NUM = 10;

  double stack_mean = 0.0;
  double heap_mean = 0.0;

  for (int i = 0; i < LOOP_NUM; i++) {
    stack_mean += count_stack(n);
    heap_mean += count_heap(n);
  }

  std::cout << "stack: " << stack_mean / LOOP_NUM << std::endl;
  std::cout << "heap: " << heap_mean / LOOP_NUM << std::endl;

  return 0;
}

結果

うーん,差が出ない...
本当は「intの方で差が出て,自作クラスの方で差がなくなる」という台本だったのですが,結果に差が出ませんでした.
このコードだとキャッシュにアドレスが残ってしまっているから?スタック領域の方が速い,どうすれば結果に表れるのでしょうか.

# int: 1億回x10試行平均 [sec]
# -Oなし
stack: 0.176563
heap: 0.179688

# -O1
stack: 0.0539063
heap: 0.05

# -O2
stack: 0.0523438
heap: 0.0484375

# -O3
stack: 0.0460938
heap: 0.05625


# 自作クラス 100万回x10試行平均 [sec]
# なし
stack: 0.195312
heap: 0.19375

# -O1
stack: 0.178906
heap: 0.179688

# -O2
stack: 0.151562
heap: 0.151562

# -O3
stack: 0.146875
heap: 0.148438