インフィニットループ 広報ブログ

2024年11月06日 (水)

著者 : s-igarashi

【GitHu部】活動ブログ

さて今回の GitHu部の活動ブログですが、正直このところあまりまとまった活動をできていませんでした。
しかしブログ記事の公開は公認部活動の数少ない義務ですから、なんとか果たしていきましょう。

というわけで、活動ブログを書くための小ネタとして、今回は PHP の文字列に潜むハッシュ値のキャッシュの実態に迫ってみました!

ハッシュ値キャッシュとは?

PHP 処理系の内部で、スクリプト内に現れる文字列型の値は zend_string という C 言語構造体によって管理されています。

PHP 8.3.7 の時点で、zend_string の定義はこのようになっています

struct _zend_string {
    zend_refcounted_h gc;
    zend_ulong        h;                /* hash value */
    size_t            len;
    char              val[1];
};

zend_refcounted_hgc が参照カウントを管理する構造体で、len が文字列の長さ、val がその長さ分の文字列(バイト列)の先頭領域を表すいわゆる struct hack であることは、PHPer でかつ C 言語を読み慣れた人ならなんとなく予想できるのではないでしょうか。問題はこの「hash value」という謎のコメントが付いた h というフィールドです。これは一体全体なんのためのフィールドなのか。

PHP は非常にハッシュテーブルを多用する言語です。PHP で使われるハッシュテーブルというのは、つまり連想配列です。PHP スクリプトの中で連想配列を色々な用途についつい使ってしまって、中に何が入っているのかよく分からなくなって大変なことになる方も多いことでしょう。それはそうと、処理系自身も内部的に多くの用途へ、スクリプト側から使う連想配列とまったく同じデータ構造を使い回しています。たとえば処理系内部では、読み込まれた全てのクラスに関する情報を持つ class_table というハッシュテーブルへ、全小文字化されたクラス名(PHP のクラス名は case-insensitive なのです!)をキーとして、クラス定義情報(=クラスエントリ)へのポインタを格納しています。そのクラス定義情報の中にも、プロパティ定義情報へアクセスするための表、プロパティテーブルがプロパティ名をキーとするハッシュテーブルとして存在します。

こういった頻繁に行われるハッシュテーブルアクセスの際、都度都度で文字列のハッシュ値を計算していくのでは無駄が大きいです。そこで PHP 処理系は文字列を表現する構造体そのものに、一度計算したハッシュ値を格納するようにしています。文字列データが処理系内に生成された最初の時点ではこのフィールド h の値は 0 なのですが、配列アクセス時のキーとして利用した際など何らかの理由でハッシュ値計算が行われた時点で、計算済の値がキャッシュされます。以降はハッシュ値が必要なら再計算をせず、保存済の値を使えるというわけです。

ハッシュ値キャッシュは実際どのくらい使われているのか?

さて、実際のところ、ある PHP プロセスの内部でハッシュ値を計算済の文字列はどのくらいあって、またハッシュ値未計算の文字列というのはどのくらい存在するものなのでしょうか?

PHP プロセスの内部情報を解析する Reli というツールを使って、試しに集計してみました!

まずはちょうど手元で動いていた PHP ツールを対象にメモリ解析をしてみます。

sudo reli i:m -p 43335 >memory_analyzed.json

手に入れた解析データを jq で計算し、まずは解析時点のメモリ上でハッシュ値キャッシュ用のフィールド h の値が 0 だったものを集計してみます。

cat memory_analyzed.json | jq '..|objects|select(."#type"=="StringContext")|select(."#locations"[0].hash == 0)' | jq -s 'length'
1879

1879 件と出ました!

続いてハッシュ値キャッシュ用のフィールド h が非 0 のものも集計してみます。

cat memory_analyzed.json | jq '..|objects|select(."#type"=="StringContext")|select(."#locations"[0].hash != 0)' | jq -s 'length'
105953

10 万越え、圧倒的ですね!!

計算値の活用率や細かい用途はさすがに分かりませんが、どうやら処理系内では大部分の文字列が何らかの経緯でハッシュ値を計算済の状態で存在する、ということは間違いないようです。

ちょっと面白いですね!

以上、今回の GitHu 部の活動ブログでした!

 

【インフィニットループの社内制度と採用情報】

他の公認部活の紹介
休暇や補助、無料ドリンクなど日々進化中の社内制度
現在募集中の採用情報
社内見学もできるバーチャル会社説明会
※YouTube動画リンクなので音声が再生されます

 


最新情報は公式ツイッター@iloop_sapporo@iloop_sendaiで発信中!