hideden.hatenablog.com

はてなぶろぐー。URLなげー。

mod_perlで親プロセスとのCopy on Writeな共有メモリを増やす方法。

大量にアクセスがあってMaxClientを大きく設定したい場合、Apacheの1プロセスあたりのメモリを少なくするのが重要。当然アプリ側で大きなライブラリを読み込まずに画像の変換はGearmandにタスクとして投げたりとかの工夫するのも有効だが、fork元になるApacheの親プロセスと子プロセス間でできる限りCopy on Writeな共有メモリを増やすのも有効。

その辺の詳しい仕組み等の話はnaoyaさんがd:id:naoya:20080212:1202830671でしてるのでそこを参考に。linuxカーネルまわりの仕組みって楽しいよね。会社の案件ではFreeBSDサーバーも結構あるんだけどFreeBSDではどうなるのかは知らない。

で、社内にXenなテストサーバーがあるのでまっさらな環境で色々実験してみた。・・・過程を全部書こうとしたら長くなったので省略。地味にpsしたり/proc/xxxxx/smaps眺めたりそんなのです。

親プロセス側のメモリにモジュールを持たせる方法

基本はとにかくstartup.plでuseして置くこと。apacheのconfigに

PerlRequire /path/to/startup.pl

等を記載しておき、その中で使用しているアプリケーションのモジュールを列挙する。業務ではSledgeを使用しているので、コントローラーやモデル等をひたすらuseする。

startup.pl

use strict;
use lib qw(/home/test/lib);

use TestApp::Pages ();
use TestApp::Pages::Root ();
use TestApp::Pages::Base ();
use TestApp::Data::Base ();
use TestApp::Data::Member ();
....(略

1;

こんな感じ。use Hoge ();と()を付け、関数のexportを抑止する。これだけでも結構共有メモリは増える。また、forkは親プロセスの複製になるので、こうやって事前にuseしてソースをコンパイル済みにしておくと子プロセス側でコンパイルするコストが節約でき、MaxRequestPerChildを小さめに設定してある&大量にアクセスがあり頻繁に子プロセスが再forkされるようなシステムだと負荷も軽くなるという効果もある。

・・・で、終わり。

だとつまらないので、これの問題点。

useはすべてのソースの実行前に読み込まれるからいいのだが、CGI.pmのように利用されるメソッドのみAUTOLOADで初回利用時にevalで生成している場合や、LWPのようにモジュールの使われ方によってrequireするサブモジュールを変えるもの、DBIのようにconnect時にドライバを読むようなものはこれでは初期化されないため、親プロセス側で共有されない。また、XSを利用しているモジュールはuseしただけでは.soが読み込まれないためこれまた共有されない。

いくつかのモジュールではmod_perlfastcgi用に初期化の方法を提供しているので素直にそれを使う。この辺の話はhttp://iandeth.dyndns.org/mt/ian/archives/000624.htmlがとても詳しいので参考にさせてもらう。

use DBI ();
DBI->install_driver("mysql");

use CGI;
CGI->compile(:cgi);

等。でも、

1. perldoc で文字列 'mod_perl' を検索してみる
2. モジュールのソースコードから、文字列 'MOD_PERL' を検索してみるれることがわかります。
3. それでも見つからないなら、startup.pl の中でメソッドを実行しておいちゃう

らしいのだが、1と2に該当するモジュールがほとんどない。。。でも全部実行するのも大変。。

動的にロードされるモジュールを調べる方法

全モジュールのソースを読む。だと半端無くきついので、Perlは一度読み込んだファイルを%INCに入れていくのを利用してみる。CPANを検索して見たところ、Module::Useとかもろその用途に使えそうなのがあるのだが、作成されたのがPerl5.6の頃らしく5.8では動かなかった。パッチを作ろうと思ったが常用するものでもない&数行で実現できるので自分で書いてみた。

INCdiff.pm

package INCdiff;
use strict;
use Apache::Constants qw(OK);
use vars qw(%init_module);

sub init { $init_module{$_}++ for keys %INC; }

sub handler {
    my @required = grep { !$init_module{$_} } keys %INC;
    warn "-------- module diff ---------";
    warn join "\n", @required;
    return OK;
}
1;

これだけ。まずこれをstartup.plの最下部で

use INCdiff;
INCdiff->init;

としておく。で、apacheのconfigに

MaxRequestsPerChild 100

PerlChildExitHandler INCdiff

と書いておく。PerlChildExitHandlerはMaxRequestsPerChild回アクセスを処理したapache子プロセスが死ぬときに呼ばれるHandlerなので、アクセスがさほど無いサーバーでMaxRequestsPerChildを大きく設定しているとなかなか表示されないかも。

後はtail -f でerror_logを見ながらユーザーがいっぱいアクセスしてくれるのを待つ。ab等のツールを使うときは全ページ・全機能がまんべんなく使われるようにしないとあまり意味がなくなる。テストサーバー等でやる場合、全モジュールが使用されるよう手動でアクセスしてからab等で残ったRequest数を消化すると楽。

しばらく待つと、startup.plの初期化が終わってからapacheの子プロセスが死ぬまでの間にロードされたモジュール(Compile済のTTテンプレなども含まれる)がずらずらと出るので適当に整形してstartup.plに追加していく。

某サービスだと、

Compress/Raw/Zlib.pm
Compress/Zlib.pm
Crypt/Blowfish.pm
DateTime/TimeZone/Asia/Tokyo.pm
DateTime/TimeZone/OlsonDB.pm
Encode/CJKConstants.pm
Encode/JP.pm
Encode/JP/JIS7.pm
File/GlobMapper.pm
HTML/HeadParser.pm
HTTP/Cookies.pm
HTTP/Cookies/Netscape.pm
HTTP/Headers/Util.pm
HTTP/Request/Common.pm
IO/Compress/Adapter/Deflate.pm
IO/Compress/Base.pm
IO/Compress/Base/Common.pm
IO/Compress/Gzip.pm
IO/Compress/Gzip/Constants.pm
IO/Compress/RawDeflate.pm
IO/Compress/Zlib/Extra.pm
IO/Select.pm
IO/Uncompress/Adapter/Inflate.pm
IO/Uncompress/Base.pm
IO/Uncompress/Gunzip.pm
IO/Uncompress/RawInflate.pm
LWP/Authen/Digest.pm
LWP/Protocol/http.pm
Net/HTTP.pm
Net/HTTP/Methods.pm
SOAP/Transport/HTTP.pm
Template/Plugin.pm
Template/Plugin/Date.pm
Template/Plugin/URL.pm
URI/_server.pm
URI/http.pm

等、結構な量が出力された。MaxClientsを多めに設定してあるサーバーでこの辺を全部useしておくと、全体でメモリ使用量が200MBほど少なくなった。XS系のモジュールの場合はこの方法ではわからないので、/proc/PROCESS_ID/smaps等を見ながら.soを見ていくと何がロードされているのかわかる。例えばApache::Requestの場合はstartup.plでnewするとエラーになってしまうため、

use Apache::Request ();
eval { Apache::Request->new(); };

等としてやればちゃんとi686-linux/auto/Apache/Request/Request.soがshared_dirtyになってる事が確認できた。これで大体70〜75%ほどが共有メモリになった。

x演算子のメモリの使い方。

10MBのダミーデータをメモリ上に確保しようと思ったらよくわからないことが。

[hideden@hideden-x61]$ perl -e '$a = "." x (10*1024*1024); sleep 60;' &   
[1] 7433
[hideden@hideden-x61]$ perl -e '$a = "."; $a x= 10*1024*1024; sleep 60;' &
[2] 7434
[hideden@hideden-x61]$ ps auxww | grep \[p\]erl                       [~] 18:36
hideden   7433  0.3  1.0  26680 21760 pts/9    SN   18:36   0:00 perl -e $a = "." x (10*1024*1024); sleep 60;
hideden   7434  0.2  0.5  16436 11520 pts/9    SN   18:36   0:00 perl -e $a = "."; $a x= 10*1024*1024; sleep 60;

$aの中身はどっちも同じになる。Devel::Sizeのsizeとかを使って調べると値は同じ。でもプロセスのメモリ使用量は約2倍。

GCまわりとかだろうかなと予想してみる。違うのかな。うーん。Perlって難しいね。

この謎の10MBは、x演算子が一時的に使ったものなんだろうか。スコープ抜けたら消えるのかなとか思って色々やってみたけど開放されず。でかいスクリプトとかだとどっかのタイミングで開放されるのかな・・・?

うーん。謎だ。らくだ本とかに載ってるのかな。帰ったら読んでみよう。




一応perl -V

[hideden@hideden-x61]$ perl -V                                        [~] 18:37
Summary of my perl5 (revision 5 version 8 subversion 8) configuration:
  Platform:
    osname=linux, osvers=2.6.22-gentoo-r8, archname=i686-linux
    uname='linux hideden-x61 2.6.22-gentoo-r8 #2 smp fri oct 5 12:40:55 jst 2007 i686 intel(r) core(tm)2 duo cpu t7300 @ 2.00ghz genuineintel gnulinux '
    config_args='-des -Darchname=i686-linux -Dcccdlflags=-fPIC -Dccdlflags=-rdynamic -Dcc=i686-pc-linux-gnu-gcc -Dprefix=/usr -Dvendorprefix=/usr -Dsiteprefix=/usr -Dlocincpth=  -Doptimize=-O3 -march=prescott -mfpmath=sse -msse -msse2 -msse3 -pipe -fomit-frame-pointer -Duselargefiles -Dd_semctl_semun -Dscriptdir=/usr/bin -Dman1dir=/usr/share/man/man1 -Dman3dir=/usr/share/man/man3 -Dinstallman1dir=/usr/share/man/man1 -Dinstallman3dir=/usr/share/man/man3 -Dman1ext=1 -Dman3ext=3pm -Dinc_version_list=5.8.0 5.8.0/i686-linux 5.8.2 5.8.2/i686-linux 5.8.4 5.8.4/i686-linux 5.8.5 5.8.5/i686-linux 5.8.6 5.8.6/i686-linux 5.8.7 5.8.7/i686-linux  -Dcf_by=Gentoo -Ud_csh -Dusenm -Di_ndbm -Di_gdbm -Di_db'
    hint=recommended, useposix=true, d_sigaction=define
    usethreads=undef use5005threads=undef useithreads=undef usemultiplicity=undef
    useperlio=define d_sfio=undef uselargefiles=define usesocks=undef
    use64bitint=undef use64bitall=undef uselongdouble=undef
    usemymalloc=n, bincompat5005=undef
  Compiler:
    cc='i686-pc-linux-gnu-gcc', ccflags ='-fno-strict-aliasing -pipe -Wdeclaration-after-statement -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -I/usr/include/gdbm',
    optimize='-O3 -march=prescott -mfpmath=sse -msse -msse2 -msse3 -pipe -fomit-frame-pointer',
    cppflags='-fno-strict-aliasing -pipe -Wdeclaration-after-statement -I/usr/include/gdbm'
    ccversion='', gccversion='4.2.2 (Gentoo 4.2.2 p1.0)', gccosandvers=''
    intsize=4, longsize=4, ptrsize=4, doublesize=8, byteorder=1234
    d_longlong=define, longlongsize=8, d_longdbl=define, longdblsize=12
    ivtype='long', ivsize=4, nvtype='double', nvsize=8, Off_t='off_t', lseeksize=8
    alignbytes=4, prototype=define
  Linker and Libraries:
    ld='i686-pc-linux-gnu-gcc', ldflags =' -L/usr/local/lib'
    libpth=/usr/local/lib /lib /usr/lib
    libs=-lpthread -lnsl -lgdbm -ldb -ldl -lm -lcrypt -lutil -lc
    perllibs=-lpthread -lnsl -ldl -lm -lcrypt -lutil -lc
    libc=/lib/libc-2.6.1.so, so=so, useshrplib=false, libperl=libperl.a
    gnulibc_version='2.6.1'
  Dynamic Linking:
    dlsrc=dl_dlopen.xs, dlext=so, d_dlsymun=undef, ccdlflags='-rdynamic'
    cccdlflags='-fPIC', lddlflags='-shared -L/usr/local/lib'


Characteristics of this binary (from libperl): 
  Compile-time options: PERL_MALLOC_WRAP USE_LARGE_FILES USE_PERLIO
  Built under linux
  Compiled at Jan  6 2008 23:25:55
  @INC:
    /etc/perl
    /usr/lib/perl5/vendor_perl/5.8.8/i686-linux
    /usr/lib/perl5/vendor_perl/5.8.8
    /usr/lib/perl5/vendor_perl
    /usr/lib/perl5/site_perl/5.8.8/i686-linux
    /usr/lib/perl5/site_perl/5.8.8
    /usr/lib/perl5/site_perl
    /usr/lib/perl5/5.8.8/i686-linux
    /usr/lib/perl5/5.8.8
    /usr/local/lib/site_perl
    .

レキシカルスコープやらシンボルテーブルやら型グロブやら。

メモっとく。

use strict;
our $hoge = 'HOGE';
my  $hoge = 'hoge';

print $hoge;            # hoge
print ${hoge};          # hoge
print $::hoge;          # HOGE
print $main::hoge;      # HOGE
print $::main::hoge;    # HOGE
print ${*hoge{SCALAR}}; # HOGE 型グロブからスカラー変数のリファレンスもらってデリファレンス

no strict 'refs';
my  $name = 'hoge';
sub name { 'hoge' };

print ${"hoge"};        # HOGE
print $$name;           # HOGE
print ${$name};         # HOGE
print ${name()};        # HOGE シンボリックリファレンスは名称orリファレンスを返す関数呼び出しでも可

になる。

  • Perl にはシンボルテーブルとレキシカルスコープの2種類の変数名テーブルがあるらしい
  • シンボルテーブルは名前空間(package)に所属。明示しなければmain空間
  • my 宣言を何のスコープにもかかってないところで行っても、global変数にはならない (ファイルスコープのレキシカル変数になる)
  • $hogeと${hoge}は完全に等価。${"hoge"}はシンボリックリファレンスのデリファレンス
  • シンボリックリファレンスのデリファレンスは、シンボルテーブルに登録されたglobal変数のみが対象
  • 型グロブで色々やるのはシンボルテーブルの話。レキシカルスコープのはいじれない

最初の宣言を逆にすると

use strict;
my  $hoge = 'hoge';
our $hoge = 'HOGE';

print $hoge;            # HOGE
print ${hoge};          # HOGE
print $::hoge;          # HOGE
print $main::hoge;      # HOGE
print $::main::hoge;    # HOGE
print ${*hoge{SCALAR}}; # HOGE

no strict 'refs';
my  $name = 'hoge';
sub name { 'hoge' };

print ${"hoge"};        # HOGE
print $$name;           # HOGE
print ${$name};         # HOGE
print ${name()};        # HOGE

全部"HOGE"になる。で、こういうことをしてみる。

use strict;

our $hoge = 'HOGE';
print \$::hoge;       # SCALAR(0x814eccc)
print \$hoge;         # SCALAR(0x814eccc)

my $hoge = 'hoge';
print \$::hoge;       # SCALAR(0x814ecb4)
print \$hoge;         # SCALAR(0x814eccc)
use strict;

my $hoge = 'hoge';
print \$::hoge;       # SCALAR(0x814ecd8)
print \$hoge;         # SCALAR(0x814eca8)

our $hoge = 'HOGE';
print \$::hoge;       # SCALAR(0x814ecd8)
print \$hoge;         # SCALAR(0x814ecd8)
use strict;

print \$::hoge;       # SCALAR(0x814ecb4)

my $hoge = 'hoge';
print \$::hoge;       # SCALAR(0x814ecb4)
print \$hoge;         # SCALAR(0x814eca8)
{
    my $hoge = 'hogehoge';
    print \$hoge;     # SCALAR(0x814eccc)
}
use strict;

print \$::hoge;       # SCALAR(0x814ecb4)

our $hoge = 'hoge';
print \$::hoge;       # SCALAR(0x814ecb4)
print \$hoge;         # SCALAR(0x814ecb4)
  • 突然Global変数にアクセスしても勝手に作成される
  • use strict; でもパッケージ名付けると怒られない
  • my はレキシカルスコープのみに変数を登録し、ourはシンボルテーブルとレキシカルスコープの両方に登録する
  • our はglobal変数だけじゃなく、レキシカル変数も上書き宣言する
  • our は既に存在するglobal変数を宣言しても別に何も怒らない
  • 違うレキシカルスコープでmy宣言すると新しく割り当てられる


この調べ方が正しいかどうかは謎。でも個人的には色々納得できた。きっかけはd:id:a666666:20080124:1201177376
初めてらくだ本読んだ!ありがとう刺身さま。

ってか、eval()の場合とかlocalがどーなんだとか型グロブ云々だとか変数の探索順だとか色々調べたけど面倒だから略。
our → my で宣言すると同じ名前に見えて中身が違うとかやれるのがちょっと新鮮だった。

ckw + NYACUS2.22aでサイズ変更時に自動でwidth設定

いまいち微妙だけどnyacusのpatch作った。
Win32プログラムと違ってサイズ変更時に WM_SIZING とか飛んできたりしないため、結局プロンプト表示する際にGetConsoleScreenBufferInfoでサイズを取得してリサイズする事にした。リサイズ後、一度何も入力せずにEnterでプロンプト再表示すれば現在の幅でwidthが設定されるはず。

コマンド入力途中に窓大きくしたい場合とかには無理だけど、、そういう場合は『 ^A -> ^K -> Enter -> ^Y 』とかやる感じで。

これでckwで最大化した場合とかに画面端までいっぱいにコマンドが入力できる。80文字の所で変に切れてるのにすごく違和感を感じてたから、とっても快適だ。nyacus最高。

nyacus222a_mod.zip

パッチ同梱。オープンソースってこういう時直せるからいいね。

ckw改造版の修正版とuberboxの修正版と簡易電卓っぽいの。

08.12.03追記
最近の性能のいいPCだとckwのConsoleを隠す処理が失敗してConsoleが出たままになったりするようです。
修正したバージョンを公開された方がいらっしゃるようなのでそちらもご参照ください。
d:id:s-yata:20080823:1219474577
http://blogs.wankuma.com/shuujin/archive/2008/10/15/158825.aspx

色々放置ですいません。。。。
/追記







http://nocd5.blog59.fc2.com/blog-entry-195.html

で修正したほうがいいところを教えてもらったので、反映してコンパイル。ありがとうございました。

ckw-0.8.10-mod2-bin.zip
ckw-0.8.10-mod2-src.zip


nocd5さんのbbLean modを使わせてもらっているので、shadeの時に小さくなるの調べなきゃーっと思ってたのでうれしい限り。これでかなり便利に。あとはnyacusがサイズ変更時にwidthを自動で更新してくれると最高なんだけどなぁ。今度見てみよう。

で、bbLeanってとても便利なんですよ。軽いし。仕事用PCの画面がXGAと若干狭く、タスクバーとか邪魔で邪魔で。検索したところnocd5さんのbblean modが更新も活発でなにより日本語だった(笑)ので、とっても細いタスクバーになるようにテーマを作成してとても快適に使わせてもらってます。せっかくなのでbblean周りをいくつか。

とにかく画面領域を限りなく広くってことを前提なので、あんまりかっこよさとかはありません。

スクリーンショット
http://hideden.net/pub/compact.zip:bblean用とにかく細いテーマ

で、このbbleanが結構プラグインが多くて楽しいんですが、せっかく画面を広く使うためにシェル変えてるのにごたごたと色々配置すると元も子もないのでubarboxっていうコマンドラインランチャをこれまた細くしてタスクバー(bbLeanBar)に一体化してるように見える位置に置いてます。SSだと左上の『□』より左がコマンドランチャになってます。

タイトルバーも同様に細くしてあるので、タイトルバーとタスクバーあわせても普通のタイトルバーくらいの太さにしかなりません。


bblean用のコマンドラインランチャPluginは3つくらいあるんですけど、bbZCmdExはbro@msでアクティブ化できなかったので見送り。でも、bbZCmdExにはあった電卓機能がubarboxにはない!

これは切ないって事で作りました。uberboxのaliass.rcで

s/^=(.+)/c:\tools\calc\calc_popup.exe $1/

って定義して、『=12345679*63』とか実行すると答えがポップアップされます。

内部的にはGnuWin32のcalcコマンドを呼び出して計算結果を取得してるので、sinやsqrt等を使用した結構高度な計算が可能です。GnuWin32のページからBinariesDependenciesをダウンロードし、解凍後出来るbinフォルダの中にあるcalc.exe, calc2.dll, readline5.dllをcalc_popup.exeと同じフォルダに入れてください。

calc_popup.zip

で、これでいいはずなんですが、ubarboxの最新版にバグがありまして、 '&' と '(' が入力できないので計算が使い物にならないんですよ。なのでubarboxの入力できないバグを修正したものが

ubarbox-fix.zip

になります。ベースはuberbox-0.1.3です。



explorerを捨ててでも画面小さいNotePCを出来る限り広く使いたい!っていう人にはお勧めです。

cmd.exeを超便利にする ckw 0.8.10 を改造した。

hideden2007-11-15


08.12.03追記
最近の性能のいいPCだとckwのConsoleを隠す処理が失敗してConsoleが出たままになったりするようです。
修正したバージョンを公開された方がいらっしゃるようなのでそちらもご参照ください。
d:id:s-yata:20080823:1219474577
http://blogs.wankuma.com/shuujin/archive/2008/10/15/158825.aspx

色々放置ですいません。。。。
/追記



※修正版をアップしました。 d:id:hideden:20071123:1195822428



6月の転職を機にメインの作業環境をGentooLinuxに変更して快適なLinuxライフを送っていたのだが、ちょっとわけあって一時的にXPに戻す事になった。今年の初めから5月末まではOSXだったから、久々のWin環境。

何でもかんでもConsole + zshって環境に慣れた今、scpでファイルひとつコピーするにもWinSCPを起動する現状は非常に面倒。ファイルもエクスプローラーで・・・ってのがとてつもなくだるい。いちいちフォルダの横の + とかクリックしてられるか!っと。

かといって、DOS窓は非常に使い勝手が悪い。文字でかいしコピペしづらいし。Cygtermを改造してcmd.exeをPuTTY経由で操作するようにもしてみたんだが、なんかリピートがおかしかったりで今ひとつ。

素直にCygwin使えよって声が聞こえてきそうだが、以前から使ってはいたものの、実はCygwinってあんまり好きじゃない。Winを使うからには別に/じゃなくc:\でいいんだよね。じゃないとFirefoxでDLしたファイルをデスクトップからいちいちc:\homeに移動したり、レジストリいじくってデスクトップの位置を変更したりとかしなきゃならない。

そもそもネイティブのFileSystemが/cygdrive/c/とか以下に出るのがなんとも。

cd /cygdrive/c/Documents\ and\ Settings/hideden/デスクトップ

とか個人的になんか気持ち悪い。

そんな中、そもそもcmd.exeの代替となるものはないのか?っと思って検索してたところ、ckwというのがとても便利だと見かけた。が、、、配布元が404・・・。


・・・っと、前置きがえらく長くなったが、結論としてarchive.orgにあるミラーからソースのみ取得することが出来た。

配布元によるとライセンスはGPLらしいので、いくつか気になった点を改造した。

  • 設定ファイル名を ckw.txt → ckw.cfg に変更 (個人的な好みです。)
  • MakefileからCygwin依存のシェルスクリプトをbatに書き換え、VCでコンパイルできるようにした
  • カレントディレクトリを指定する-cd,--chdir を追加
    • -e cmd.exe /K cd c:\とかでも行けるが、他シェル等でも楽にするため。
  • 実行シェルを設定ファイルに記述できるようにした
    • -eオプションで指定できていたが、ショートカットをいじるのが面倒だったため。
  • タイトルを指定するオプション-tl,--titleを追加
    • cmd用とnyacus用を見分けやすくしたくて。
  • フォントサイズを標準のDOS窓より小さく設定すると、最大化や窓リサイズで一定以上の大きさになるとウィンドウサイズがおかしくなってしまう不具合を修正(多分)
    • MS Gothic 12で最大化するとなんかタイトルバーのみの小さな窓になってしまっていた。

こんな所。一番の問題は最大化で窓が極小になってしまうところ。どうやらオリジナルのDOS窓でのフォントサイズと画面解像度から算出された縦横の文字数を超えるとおかしくなっていた模様。XGAだと横125文字以上になるとおかしくなる。

で、kernel32.dllにあるSetConsoleFontなる隠しAPIを使って、非表示にしてあるDOS窓のフォントサイズを極小に設定することで回避。

元々C/C++は見よう見まねでやってるので、挙動がおかしい部分があればぜひ指摘していただければ。

って事で、オリジナルソースのmirrorとオリジナルのバイナリ、改造版のバイナリ・ソースをうpっておく。GPLだし問題ないと思うが、なんか問題があればコメントとかnowa経由等でご指摘ください。コンパイルはVC8(VisualStudio2005)で行った。

オリジナル
http://hideden.net/pub/ckw-0.8.10-src.zip
http://hideden.net/pub/ckw-0.8.10-bin.zip

改造版
http://hideden.net/pub/ckw-0.8.10-mod-src.zip
http://hideden.net/pub/ckw-0.8.10-mod-bin.zip


それにしてもこのソフト便利。PuTTYライクな選択でコピー、右クリックでペーストが出来るだけでなく、コンソールじゃないから普通に日本語を通常のIMEから入力できる。日本語入力をONにするとカーソル色が変わったりするのもいい。

何より、nyacusと組み合わせると最強。長くなったのでこれについてはまた後日。

作者様にとても感謝。ちょっとだけXPが好きになった。

参照カウンタ。

オブジェクトのリファレンスがつまった配列@arrayを$#arrayで短くしたとき、ちゃんと中身が開放されるのかなーって思って参照カウンタをみてみた。

#!/usr/bin/perl
use Devel::Peek qw/SvREFCNT/;

my (@a, @b);
push(@a, \$_) for (1 .. 10);
@b = @a;
$#a = 4;

print "\@a=";
print SvREFCNT($$_) for @a;
print "\n\@b=";
print SvREFCNT($$_) for @b;
[hideden@sv1]$ ./test.pl
@a=22222
@b=2222211111

ちゃんと参照カウンタは減ってる。多分開放されるんだろう。多分。