Perlテックブログ

ITエンジニアの成長意欲を刺激する技術考察、モジュール開発の日記。Perlイベントや国内や海外のPerlの記事の紹介。

リファレンスの機能を実装しつつ、変数領域作成で、mallocしない方法

現在SPVMのメモリ最適化を進めています。

今まさにやろうとしていることは、サブルーチン呼び出しを行ったときの、変数領域のメモリ最適化です。

mallocの回数を減らしたい

mallocをたくさん呼び出すことは、非常に遅いことだといわれています。

mallocを呼び出すと、システムコールが入り、指定されたサイズを元にして空いているメモリ領域を探します。

そして、メモリを確保して、その先頭のアドレスを返します。

これらの処理が重いといわれています。

パフォーマンスを高めるためには、できるだけmallocを減らすことが必要なのです。

リファレンスを実装しているので、メモリ領域が移動できない

SPVMは、リファレンス機能を仕様として含んでいるので、変数として確保した領域を移動させることができないという制約があります。

だから、大きな領域を新しくとって、元のデータを移動させるということが、サブルーチンの変数のメモリ領域に対してはできないということに気が付きました。

アドレス型、byte型~double型までそれぞれの変数領域確保が必要

SPVMは、静的型言語ですが、ランタイムで実行されるときでさえ、変数の型情報を本当に持っています。

  // object variables
  void** object_vars = NULL;
  
  // ref variables
  void** ref_vars = NULL;
  
  // double variables
  SPVM_VALUE_double* double_vars = NULL;
  
  // float variables
  SPVM_VALUE_float* float_vars = NULL;

  // long variables
  SPVM_VALUE_long* long_vars = NULL;

  // int variables
  SPVM_VALUE_int* int_vars = NULL;

  // short variables
  SPVM_VALUE_short* short_vars = NULL;
  
  // byte variables
  SPVM_VALUE_byte* byte_vars = NULL;

これらの変数領域を確保するために、うまくmallocの回数を減らしてあげる必要があります。

変数の長さの最大長は65535個、変数の長さの最大長は、コンパイル時に決定できる

ふと考えていると、すべてのサブルーチンの変数の長さの最大長は、コンパイル時に決定できることがわかりました。

もし長さの最大が、54個だったとしましょう。そして、SPVMのデータ型のサイズは、SPVM_VALUE型よりも小さいことが保証されています。

とすれば、

sizeof(SPVM_VALUE) * 54

というサイズを、領域確保の固定サイズとしておけば、すべての変数領域が納められます。

mallocして、最初は一つ確保、足りなくなったこのサイズで追加します。

# sizeof(SPVM_VALUE) * 54
-------------------

# sizeof(SPVM_VALUE) * 54
-------------------

サブルーチンが一番最初の呼び出し位置に戻ると、この領域を再利用します。

そうすると、リファレンス機能を維持しつつ、プログラム全体で、サブルーチン呼び出しの場合のmallocの回数をほんの数回に抑えることができる。

デメリット

考えられるデメリットの一つ目は、すべてのクラスを静的にコンパイル時に決める必要があることです。実行時に後から、クラスを追加するということはできなくなります。

デメリットの二つ目は、プログラムによって、確保する領域が変わるので、試験が非常に行いにくいということです。実装にミスがあった場合に、自分の試験環境ではうまく動いても、予期せぬ不具合が発見される可能性があります。