ppBlog Warning: LINE 953 of utils.php: A non-numeric value encountered:

ppBlog Warning: LINE 1008 of utils.php: A non-numeric value encountered:

ppBlog Warning: LINE 1034 of utils.php: A non-numeric value encountered:

ppBlog official

[ カテゴリー » 開発日誌 ]

IEのメモリリーク問題

category-icon

IEあるいはIEエンジンのブラウザ(Sleipnirとか)を使っていて、どうもページの描画速度が遅い気がする―もっと正確には最初にページを開いたときより遅くなった―と感じたことはないだろうか? 特にあなたがJavaScriptを多用したページを開いているならば、もしかしたらIE特有のメモリリーク問題(IE memory leaks problemG)が原因かもしれない。

 余談ですが、前回のmoblogエントリーは、自分のブログにモブログしたつもりが間違ってこちらにエントリーしてしまいました。気が向いたら移動しておきます。

 で、本題ですが、この問題はより多くの利用者が(IEエンジンの)タブブラウザーを使うようになればなるほど顕在化してくると思われるのでメモしておこうと思います。ppBlogでもJavaScriptは欠かせませんし。最初に言っておきますが、この問題はIE4-6に特有のもので他のモダンなブラウザは影響を受けません。

 では、早速、IE6単体で(タブブラウザではなく)このテストページLink を開いて下さい。216色のカラーチャートを作成し、その各セルにマウスイベントを設定しているシンプルなデモです。ページを開いたらリロードを何回か繰り返してみましょう。生成時間がどんどん長くなっているのを確認したら、そのページを一度閉じて、新たに次のテストページLink を開いて同様にリロードを繰り返してみましょう。どうでしょうか?今度は生成時間が伸びていくということはありません。

 この2つのページの違いは何でしょうか?最初のテストページでは、まさにメモリーリークが起こっています。リンク先にも書いてありますが、分かる方はControl + Alt + Del キーを押して、タスクマネージャを起動、IEXPLOERE.EXEのメモリを見ながらリロードを繰り返せばメモリが肥大化していくのを見ることができます(尚、ウィンドウを閉じればメモリは開放されます)。この2つのテストページの違いは、ほんのちょっとしたことです。やや専門的になるかもしれませんが、イベントを定義する関数を定義しているのですが、その扱いの違いです。もともとは、Scott AndrewLink (最近は専ら音楽に夢中のようです。。)がW3CとIE特有のイベント定義関数の差を吸収するために作り出したaddEvent/removeEvent関数ですが、オリジナルのままでは、IEのthis参照に問題があったために、様々なバージョンが編み出されました。ppBlog1.5βでも似たようなやつを付けていますが、ここに挙げるのはその改訂版です。まず、メモリリークを起こすやつから。

function addEvent(obj, evType, fn){
 if(!obj["_"+evType]){
  obj["_"+evType] = [];
  if(obj["on" + evType] != null) obj["_"+evType].push(obj["on" + evType]);
  obj["on" + evType] = function(e){
   var e = e || window.event;
   for(var i in this["_"+e.type]) this["_"+e.type][i].apply(this,[e]);
  }
 } else {
  for(var i in obj["_"+evType]) if(obj["_"+evType][i]===fn) return;
 }
 obj["_"+evType].push(fn);
};

function removeEvent(obj, evType, fn){
 if(obj["_"+evType]){
  for(var i in obj["_"+evType]){
   if(obj["_"+evType][i]===fn) delete obj["_"+evType][i];
  }
 }
};

 addEventの中で、匿名関数を使っています(ホナ トピンクの部分)。次にメモリリークを起こさないやつ。

function addEvent(obj, evType, fn){
 if(!obj["_"+evType]){
  obj["_"+evType] = [];
  if(obj["on" + evType] != null) obj["_"+evType].push(obj["on" + evType]);
  obj["on" + evType] = evokeEvent;
 } else {
  for(var i in obj["_"+evType]) if(obj["_"+evType][i]===fn) return;
 }
 obj["_"+evType].push(fn);
};

function removeEvent(obj, evType, fn){
 if(obj["_"+evType]){
  for(var i in obj["_"+evType]){
   if(obj["_"+evType][i]===fn) delete obj["_"+evType][i];
  }
 }
};

function evokeEvent(e) {
 var e = e || window.event;
 for(var i in this["_"+e.type]) this["_"+e.type][i].apply(this,[e]);
};

 具体的に各オブジェクトにイベントを設定していく部分をaddEvent関数の外に出していますね。おかげで関数が3つになっちゃってます。世の中の多くのJavaScriptの書き手は、「スクリプトはシンプルなのがスマートだ」という理念を持っていて、自分もその一人です。その結果として関数内の匿名関数やクロージャーを多用する傾向にあります。悲しいかな、IEにはこれが通用しないのです。もっと詳しくこの問題を理解するキーワードは、「クロージャーclosure」と「循環参照 circular reference」です。ここで詳しく解説しようとは思っていないので悪しからず。以下のサイトを参照してください。Richard CornfordのサイトLink が端的にこの問題を指摘しています。

The Internet Explorer web browser (verified on versions 4 to 6 (6 is current at the time of writing)) has a fault in its garbage collection system that prevents it from garbage collecting ECMAScript and some host objects if those host objects form part of a "circular" reference. The host objects in question are any DOM Nodes (including the document object and its descendants) and ActiveX objects. If a circular reference is formed including one or more of them, then none of the objects involved will be freed until the browser is closed down, and the memory that they consume will be unavailable to the system until that happens.

 この問題は、Microsoftも認識しているのでIE7では解決されると良いのですが。尚、上に挙げたサイトで、最後のMihaiのページもよくまとまっているのですが、Mihaiが例示しているメモリーリークの退避例でも、やはりリークが起こるような気がします。

 あと、メモリーリークを起こすページを検出するツールがあるので、これもリンクしておきます。もっとも、このツールは完璧ではなく、すべてのメモリリークを検出するわけではないですが目安にはなるかと。メモリー負荷テスト(Blow memory)は、メモリーが増大していく様を見れるので有用です(もっともタスクマネージャーでも見れますが)。

Out of Hanwell:IEメモリリーク検出ツールLink

タブブラウザが出てくる以前は、この問題はさほど気にすることもなかったかもしれませんが、タブブラウザでは、常に複数のページを開いているというのが当たり前ですし、AJAXの台頭で、これからもJavaScriptはwebページで多用されるでしょうから、この問題を認識しておくのも悪くはないと思います。自分みたいなプログラム配布者はなおさらです。

 あ、あと、スコット・アンドリューがaddEvent/removeEventについて最初に紹介したページを見付けたのでリンクしておきますね。 →http://www.scottandrew.com/weblog/articles/cbs-eventsLink


— posted by martin at 01:09 pm   commentComment [7]  pingTrackBack [2]

PHPに最悪の脆弱性 

category-icon

PHP史上最悪の脆弱性(ぜいじゃくせい)が発見されたようです。まずすべき対策は、PHP4.4.1以上にアップグレードすることのようです。が、多くの方は、独自でドメインを取っていても、レンタルサーバーなのでPHPのバージョンアップには手が出せないという状況だと思います。

 これは、暫くはサーバー会社なり管理人さんの反応を見るしかないですね。とにかく重大な脆弱性らしいです。具体的な部分を自分のブログLink に少し書きましたが、まだよく呑み込めていません。ppBlogのプログラム自体は、現時点では、怪しい箇所は思いつきませんが見直しておきます。


— posted by martin at 04:37 pm   commentComment [1]  pingTrackBack [1]

PHPでドロップシャドウ

category-icon

最近のエントリーはアップデートばかりでバランスが悪いので、たまには開発日誌を書いてみよう。

 それなりにプロ意識を持ったデザイナー達がざわざわとエントリーしてそうなDeviantARTLink のサイト。ここでは至る所で作品のサムネイル画像を目にすることができます。で、どの画像にもいい感じでドロップシャドウが利いていますね。ドロップッシャドウ自体はppBlogでも指定出来るのですが、このDeviantのサイトのように綺麗ではありません。何故なら、おそらくDeviantのサイトでは、個々のサムネイルの大きさに合わせて、動的に「影」を生成しているからです(おそらく。ソースを見た感じでの推論です)。ppBlogでは、サーバーへの負荷やパフォーマンスを考慮して、このアプローチは取っていません。何より、PHPでのドロップシャドウのプログラムは「何だかややこしそうだ」というのがありました。

 でも、画像ギャラリーのサムネイル画像で、ぜひともDeviantみたいなドロップシャドウを実現したくて勉強がてらスクリプトを書いてみました。こんな感じです。左上にある「エリア拡張ボタン」を押すと見やすいと思います。

function ImageDropShadow($from='', $output, $borderW=5){
 $size = GetImageSize($from);
 $tl_shadow = ImageCreateFromPNG("Images/top-left.png");
 $offsetX = ImageSX($tl_shadow);
 $offsetY = ImageSY($tl_shadow);
 $br_shadow = ImageCreateFromPNG("Images/bottom-right.png");
 $shadowX = ImageSX($br_shadow);
 $shadowY = ImageSY($br_shadow);

 $canvas = ImageCreateTrueColor($size[0]+$offsetX+$shadowX+$borderW*2, $size[1]+$offsetY+$shadowY+$borderW*2);
 ImageAlphaBlending($canvas, true);

 switch ($size[2]){
  case 1 : $out = ImageCreateFromGIF($from); break;
  case 2 : $out = ImageCreateFromJPEG($from); break;
  case 3 : $out = ImageCreateFromPNG($from); break;
 }
 
 $bg_color = ImageColorAllocate($canvas, 255, 255, 255);
 Imagefilledrectangle ($canvas, 0, 0, ImageSX($canvas), ImageSY($canvas), $bg_color);

 ImageCopy ($canvas, $out, $offsetX+$borderW, $offsetY+$borderW, 0, 0, $size[0], $size[1]);
 // top left
 ImageCopyResampled($canvas, $tl_shadow, 0,0, 0,0, $offsetX,$offsetY, $offsetX,$offsetY);

 $tp_shadow = ImageCreateFromPNG("Images/top.png");  // top
 ImageCopyResampled ($canvas, $tp_shadow, $offsetX,0, 0,0, $size[0]+$borderW*2,$offsetY, ImageSX($tp_shadow),ImageSY($tp_shadow));

 $tr_shadow = ImageCreateFromPNG("Images/top-right.png");  // top right
 ImageCopyResampled ($canvas, $tr_shadow, $offsetX+$size[0]+$borderW*2,0, 0,0,
                     $offsetX,$offsetY, ImageSX($tr_shadow),ImageSY($tr_shadow));

 $r_shadow = ImageCreateFromPNG("Images/right.png");  // right
 ImageCopyResampled ($canvas, $r_shadow, $size[0]+$offsetX+$borderW*2,$offsetY, 0,0,
                     $shadowX,$size[1]+$borderW*2, ImageSX($r_shadow),ImageSY($r_shadow));

 $l_shadow = ImageCreateFromPNG("Images/left.png");   // left
 ImageCopyResampled ($canvas, $l_shadow, 0,$offsetY, 0,0,
                     $offsetX,$size[1]+$borderW*2, ImageSX($l_shadow),ImageSY($l_shadow));

 $bl_shadow = ImageCreateFromPNG("Images/bottom-left.png"); // bottom left
 ImageCopyResampled ($canvas, $bl_shadow, 0,$size[1]+$offsetY+$borderW*2, 0,0,
                     $offsetX,$shadowY, ImageSX($bl_shadow),ImageSY($bl_shadow)); 

 ImageCopyResampled ($canvas, $br_shadow, $offsetX+$size[0]+$borderW*2,$offsetY+$size[1]+$borderW*2,// bottom right
                     0,0, $shadowX,$shadowY,$shadowX,$shadowY);

 $bm_shadow = ImageCreateFromPNG("Images/bottom.png"); // bottom
 ImageCopyResampled ($canvas, $bm_shadow, $offsetX,$offsetY+$size[1]+$borderW*2, 0,0,
                     $size[0]+$borderW*2,$shadowY, ImageSX($bm_shadow),ImageSY($bm_shadow)); 

 ImageDestroy($tl_shadow); ImageDestroy($tp_shadow); ImageDestroy($tr_shadow);
 ImageDestroy($l_shadow);  ImageDestroy($r_shadow);
 ImageDestroy($bl_shadow); ImageDestroy($bm_shadow); ImageDestroy($br_shadow);
 ImageDestroy($out);
 
 switch ($size[2]){
  case 1 : case 3: ImagePNG($canvas, $output); break; // GIF and PNG 
  case 2 : $out = ImageJPEG($canvas, $output); break; // JPEG to JPEG
 }
 ImageDestroy ($canvas);
}

 いやー、長い長い。メモ紙に模式図を書きながらでないと、とても頭の中だけでは無理でした。改良の余地はありそうですが、これをutils.phpに組み込んで、画像ギャラリーのサムネイル画像はそれっぽいドロップシャドウ付きで表示できるようになりました。Deviantと違う点は、Deviantはサムネイル画像とは別に、背景に影を(動的に)用意しているのですが、この上に挙げた関数で生成される影はサムネイルと一体化しています。なので、一度サムネイル画像を作ってしまえばおしまいなので、サーバー負荷などを気にする必要もありません。

 上のギャラリーアイコンをクリックして雰囲気を見てください。最初にしては、まぁまぁかなと。なお、ここのギャラリーは、まだ画像が少ないんでイマイチな感じですが、weblogの方は画像が揃っているので、なかなか見ごたえはあります→http://martin.p2b.jp/index.php?mode=galleryLink

— posted by martin at 02:15 am   commentComment [0]  pingTrackBack [0]

新しいテーマを追加してみた

category-icon

まだ細部の詰めが出来ていませんが雰囲気はつかめると思います。ちょいとシックな感じなので"ppBlog le chic"。 ブラウザ画面をスクロールしても動かないトップのナビメニューは、もうひとつのテーマ「Basic」と同じようにモダンなブラウザ(FirefoxやOpera,Safari)ではCSS(スタイルシート)のポジションに関する指定
position: fixed;
を用いて固定していますが、最もメジャーなブラウザであるIE6はこの指定には対応していません。なので、IEだけには別にIE専用のスタイルシートを読み込ませることでこの固定座標を実現しています。このサイトの二つのテーマでは、2種類の異なる方法で固定してます。詳しくは後日書こうかと思います。 ついでながら、バギーなIE6ですが、画像のPNG形式がサポートしている透過アルファチャンネルにも対応していません。なので、このppBlogでもこれまで配布していたドロップシャドウ用の「影」画像は透過情報は省いてましたが、来年の夏ぐらいには出てくるであろうIE7では透過PNGをサポートするので、それをにらんで影の画像は透過PNGファイルにしてます。ただ、これだと相変わらずIE6では透過せずに何ともみじめな「影」になってしまうので、これもスタイルシート(+スクリプト)で、透過情報を保持するようにしています。これで記事の背景色が白以外でもきれいにドロップシャドウが実現されます。これも後日記事にしようかと思います。

— posted by martin at 09:21 pm   commentComment [6]  pingTrackBack [0]

Hello, World!

category-icon

ここにppBlogの更新状況や開発日記を書いていけば良いかな。さっそくv1.5系とこれまでの1.4系とで新しくなったところを紹介してみます。
  • カテゴリー毎にに固有アイコンを付けれるようになった。まだ調整中ですが。個人的に欲しい機能だったので。アイコンがひとつ加わるだけでも何か見栄えが違います(気のせい?)。
  • コメントの付いた記事では、Ajaxを使ってその場で動的にそのコメントを表示できるようになった。AjaxG(えいじゃっくす?)とは詳しくはグーグルで検索していただくとして、簡単に言えば「JavaScriptを使って、ページを再読み込みすることなしに、サーバーとやり取りして部分的にページ内容を書き換える」こと、と言えば分かりやすいだろうか。こうすると何が嬉しいって、欲しいデータだけをサーバーから取ってこれるので、データの転送量が少なくて済み、サーバーへの負荷軽減になる。またユーザーから見れば、ページ全体を再度読み込む訳ではないので、操作にある種の連続性が得られるというか、シームレスなブロッグ体験が出来るというか、ややこしくなってきたが、ま、そういうことである。実際に試してみると分かります。コメントボタンを押すと、ちょっと間を置いて、コメントが表示されると思います。予め読み込んで非表示にしている訳ではないです。この「間(ま)」が、また良い感じ(個人的には)。とはいっても、いまどきのブロードバンドでは殆ど待たされることはないと思います
  • 3つ目としては、記事ボックスのスタイルが、かなり自由にカスタマイズ出来るようになったこと。「良いブロッグ」の条件として、個人的には「デザイン」を外すことは出来ない。ある程度、ブロッグ書きに慣れてくると、今度は差別化を図ろうとデザインに拘りたくなる。日付の位置はこっち側だとか、いや「posted by?」は上に持ってきたい、などなど。なので、記事ボックスを構成するそれらをパーツ化して、細かい調整はスタイルシートで指定するようにしました。肝心の「記事ボックス」の雛形は、各テーマディレクトリにあるtemplate.htmlの中で指定するようにしました。これだと、テーマごとに、がらりとデザインを変えることが出来ると思います。と言いつつ、まだひとつしか作ってないんだけど。。
  • 見た目はそんなところでしょうか。内部的には結構変わっています。まず、セッション管理を独自のやつに変えました。session.class.phpというクラスを作成して、それでログインなどを管理しています。パフォーマンス的にも悪くないのではと。
  • また、ブロッグの設置当初は、いろんなエラーが表示されまくりと言うのは、誰しも経験あると思いますが、このエラーハンドラーも独自のやつを用意しました。非常にシンプルなものですが。これのon/offは簡単に切り替えが効くようにする予定です。エラーが出る内は、有効にしておいて、収まってきたら無効にしておく、なんてことが可能です。開発者から見れば、細かいエラー表示は、デバッグの有用な情報となります。

— posted by martin at 08:56 am   commentComment [29]  pingTrackBack [2]

T: Y: ALL: Online:
Created in 0.0058 sec.
prev
2025.5
next
        1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31