Retractive Scroll Views for Android

今さらですがGitHubの練習がてら、Android向けのライブラリをGitHubにアップしました。
iOSみたいに、びよーんとオーバースクロールできるスクロールビューです。複数のスクロールビューを同期して動かすこともできます。Android 1.6 (API Level4)から使えます。

https://github.com/tmyymmt/Retractive-Scroll-Views-for-Android

[youtube]http://www.youtube.com/watch?v=k03AD98olUY[/youtube]
[youtube]http://www.youtube.com/watch?v=9KZgaGCwQgI[/youtube]

Scalaのススメ

遅ればせながらScalaを勉強中。これは良い。
無理矢理まとめると「Javaの静的型付けの良さはそのままに、利便性アップ、関数型言語も入れました言語。」
こんな感じな好みの人、Perl、Ruby、PHPがしっくりこなかった人には合いそう。
業務で使うには、コンパイル時のエラーチェック(静的型付け)、可読性、互換性が重要。

一度作って捨てるならアドホックでもいいけれど。業務上のメンテナンスやバージョンアップを考えたら、ある程度シンプルで万人が理解できる言語仕様であること。担当者かわったらメンテできないとか、動かさないと型の不整合なバグも発見できないとか、言語のバージョン変わったら動かないとか。そんなの業務では使いたくない。

Zipファイルのコメント by Java

  • Zipファイル内のエントリー単位のコメントは ZipEntry#getComment() で取得する。しかし、ZipFileを用いた場合は正しく取得できるが、ZipInputStreamを用いた場合はnullしか返らず取得できない。
  • Zipファイル単位のコメントは、ZipOutputStream#setComment()で書き出しはできるが、読込みのメソッドが存在しないため取得できない。
  • ファイル名のエンコードはUTF-8固定なので一般的なアーカイブツールを使って展開すると日本語が文字化け。jarコマンドでは化けない。org.apache.tools.zip.ZipOutputStream#setEncodig(String)を使えば良いらしい。
Zipファイルの扱い関してSunの人はやる気なさすぎ。
一つ目の件についてはZIPフォーマットとストリームの都合らしく「バグではない。仕様だ。」としているが、APIのJavaDocにその旨が書いてない。
二つ目はAPIを用意しなかったミスだろう。Javaは全体的な思想や考慮に良い点が多いだけにとても残念。

C++でメモリリークを検出する方法

C++@Linuxなプロジェクトでメモリリークが発生。
MemProfmtraceccmallocmpatroldmallocをチェックしたが、プロジェクトの環境で使えるのはmtraceだけだった。
しかしnew/deleteの場合はリークの存在は確認できるがソースファイル名と行番号までは出力されず(malloc/freeの場合は行番号まで出力される)。dmallocはc++のnew/deleteでも利用可能らしいのだが、いざ対象のプログラムとリンクしようとするとリンクエラーで使えない。
関連情報を調べたあげく、仕方ないので自分でコードを書いてみた。

内容としては、new、new[]、delete、delete[]、をオーバーライドまたはオーバーロードして、メモリの確保と解放のタイミングで対応をチェック。メモリ確保したのに解放されていない場合は、そのメモリを確保したソース上のファイル名と行番号を表示する。
1. DetectMemoryLeaks.hDetectMemoryLeaks.cpp をコピー。
2. DetectMemoryLeaks.cppをコンパイル対象に追加。
3. 最初にコンパイルされるソースに次の2行を追加。
    #include “MemoryLeakChecker.h”
    #define new new(__FILE__, __LINE__ )
4. メモリーリークをチェックしたい範囲の開始位置に次の1行を追加。
    memoryLeakCheckerCheckStart(std::cout);
5. メモリーリークをチェックしたい範囲の終了位置に次の1行を追加。
    memoryLeakCheckerCheckEnd(std::cout);
6. 対象をコンパイルして、実行すればOK。
使い方のサンプルはこちら(MemoryLeaksSample.cpp)。
注意:マルチスレッドは考慮していません。detectMemoryLeaksStart/End呼び出しの入れ子は考慮していません。

DetectMemoryLeaks.cpp の内容。

std::map detectMemoryLeaksMemoryMap;
bool detectMemoryLeaksFlag = false;

void *
operator new(std::size_t size, char * pszFileName, int nLineNum)
throw (std::bad_alloc)
{
    void * address = malloc(size);
    if(address == 0)
        throw std::bad_alloc();
   
    if(detectMemoryLeaksFlag){
        // std::cout << “new: ” << pszFileName << “:” << nLineNum << ” size=” << size << ” address=” << address << std::endl;
        std::ostringstream oss;
        oss << pszFileName << “:” << nLineNum << ” size=” << size  << ” address=” << address;
        detectMemoryLeaksMemoryMap.insert( std::pair((std::size_t)address, oss.str()) );
    }
    return address;
}

void *
operator new[](std::size_t size, char * pszFileName, int nLineNum)
throw (std::bad_alloc)
{
    void * address = malloc(size);
    if(address == 0)
        throw std::bad_alloc();
   
    if(detectMemoryLeaksFlag){
        // std::cout << “new[]: ” << pszFileName << “:” << nLineNum << ” size=” << size << ” address=” << address << std::endl;
        std::ostringstream oss;
        oss << pszFileName << “:” << nLineNum << ” size=” << size  << ” address=” << address;
        detectMemoryLeaksMemoryMap.insert( std::pair((std::size_t)address, oss.str()) );
    }
    return address;
}

void
operator delete(void * address)
{
    if(address == 0) // Depends on environment.
        return;
   
    if(detectMemoryLeaksFlag){
        // std::cout << “delete: ” << ” address=” << address << std::endl;
        std::map::iterator it = detectMemoryLeaksMemoryMap.begin();
        std::map::iterator itEnd = detectMemoryLeaksMemoryMap.end();
        std::size_t checkAddress = (std::size_t)address;
        for(; it!=itEnd; it++){
            if(it->first == checkAddress){
                detectMemoryLeaksMemoryMap.erase(it);
                break;
            }
        }
    }
    free(address);
}

void
operator delete[](void * address)
{
    if(address == 0) // Depends on environment.
        return;
   
    if(detectMemoryLeaksFlag){
        // std::cout << “delete[]: ” << ” address=” << address << std::endl;
        std::map::iterator it = detectMemoryLeaksMemoryMap.begin();
        std::map::iterator itEnd = detectMemoryLeaksMemoryMap.end();
        std::size_t checkAddress = (std::size_t)address;
        for(; it!=itEnd; it++){
            if(it->first == checkAddress){
                detectMemoryLeaksMemoryMap.erase(it);
                break;
            }
        }
    }
    fr
ee(address);
}

void
detectMemoryLeaksStart(std::ostream& ros)
{
    ros << “[detect memory leaks] start” << std::endl;
    detectMemoryLeaksFlag = true;
}

void
detectMemoryLeaksEnd(std::ostream& ros)
{
    ros << “[detect memory leaks] end” << std::endl;
    if(detectMemoryLeaksMemoryMap.size() > 0){
        ros << “memory leaks …” << std::endl;
        std::map::iterator it = detectMemoryLeaksMemoryMap.begin();
        std::map::iterator itEnd = detectMemoryLeaksMemoryMap.end();
        for(; it!=itEnd; it++)
            ros << ”  ” << it->second << std::endl;
    }else{
        ros << “memory leak is nothing.” << std::endl;
    }
    detectMemoryLeaksFlag = false;
    detectMemoryLeaksMemoryMap.clear();
}

にしても、今時C++を使うのは正直どうかと。よほどメモリやCPUが限られた条件では仕方ないかもしれないが。チームでソフトを作る際にC++を使うと細かいことまで事前に決めないとぐちゃぐちゃになるし。各種ライブラリも構成やネーミングに統一感無いし。ハードの性能向上速度、メンバーの教育、コーディングルールの策定と厳守、デバッグ、可読性を考慮して、ソフトのサイクルをトータル的考えると効率が悪い。GCの最大時間が保障されたJavaVM使った方がトータルコストも下がるし安全だし効率が良いと思う。(GC領域を限定すれば時間保障は確保できるだろう。)

CDT 4.0 – Call Hierarchy

CDT4.0で待望の「Call Hierarchy」が使えるようになった。

あと、Eclipseに必要なプラグインを同梱したパッケージがいくつか提供されるようになったらしい。それにThird Party Distros紹介も。
いろいろなプラグインを個々で入れるとよくプラグイン同士のバージョンの不整合でさまざまな問題が発生するのでありがたい。
  Eclipse IDE for Java Developers, for Java EE Developers, for C/C++ Developers, Eclipse for RCP/Plug-in Developers, Eclipse Classic
  Third Party Distros: RoweBots, nexB, Innoopract