私はPHPでパーサーを作成していますが、これは大きなメモリ内文字列を処理できる必要があるため、これはやや重要な問題です。(つまり、「時期尚早に最適化」して私を炎上させないでください)
関数はどのようにsubstr
機能しますか?文字列データの2番目のコピーをメモリに作成しますか、それとも元のデータを参照しますか?$str = substr($str, 1);
たとえば、ループで呼び出すことを心配する必要がありますか?
私はPHPでパーサーを作成していますが、これは大きなメモリ内文字列を処理できる必要があるため、これはやや重要な問題です。(つまり、「時期尚早に最適化」して私を炎上させないでください)
関数はどのようにsubstr
機能しますか?文字列データの2番目のコピーをメモリに作成しますか、それとも元のデータを参照しますか?$str = substr($str, 1);
たとえば、ループで呼び出すことを心配する必要がありますか?
効率を本当に検討している場合は、文字列にポインタ(つまりインデックス)を保持する必要があります。多くの文字列関数は、操作を開始するためのオフセットを受け入れます(strpos()
の3番目のパラメーターなど)。通常、この機能をラップするオブジェクトを作成することをお勧めしますが、それを頻繁に使用することを期待している場合は、パフォーマンスのボトルネックが発生する可能性があります。これが私が意味することの例です(OOなし):
while ($whatever) {
$pos = strpos($string, $myToken, $startIndex);
# do something using $pos
$startIndex = $pos;
}
必要に応じて、これらの文字列操作を実行する独自のラッパークラスを作成し、速度に影響があるかどうかを確認できます。
class _String {
private $string;
private $startIndex;
private $length;
public function __construct($string) {
$this->string = $string;
$this->startIndex = 0;
$this->length = strlen($string);
}
public function substr($from, $length = NULL) {
$this->startIndex = $from;
if ($length !== NULL) {
$this->endIndex = $from + $length;
}
}
# other functions you might use
# ...
}
Chadのコメントをさらに進めるために、コードでは両方の文字列(完全な文字列と完全な1マイナス最初の文字)が同時にメモリに存在する必要があります(ただし、Chadが述べた割り当てによるものではありません)。見る:
$string = str_repeat('x', 1048576);
printf("MEM: %d\nPEAK: %d\n", memory_get_usage(), memory_get_peak_usage());
substr($string, 1);
printf("MEM: %d\nPEAK: %d :-(\n", memory_get_usage(), memory_get_peak_usage());
$string = substr($string, 1);
printf("MEM: %d\nPEAK: %d :-(\n", memory_get_usage(), memory_get_peak_usage());
次のようなものを出力します(メモリ値はバイト単位です):
MEM: 1093256
PEAK: 1093488
MEM: 1093280
PEAK: 2142116 :-(
MEM: 1093276
PEAK: 2142116 :-(
はい。反復ごとに文字列の新しいコピーが生成されるため、ループ内で文字列を操作する場合は注意が必要です。