アカウント名:
パスワード:
GCを利点として挙げる人がいますが、それも僕はどうかと思っています。 GCがあるためにむちゃくちゃなプログラムでもある程度動いてしまいます。
GC を単にメモリリークを防ぐためのものと考えると大したありがたみはありませんが,メモリフラ
確認ですが、
Java の Heap に関しては、激しくオブジェクトの生成/回収を繰り返してもフラグメンテーションによって新規オブジェクトが生成できない、とゆー事態には陥ったことがない
というのは、異なるサイズのオブジェクトを生成、回収した場合ですか? というのは、同じサイズばっかりだったらそもそも空きメモリの断片化は問題にならないはずなので。
ちなみに、アドレス空間を長持ちさせると(Unixのkernelはその典型)、オブジェクトの生成にともなう再初期化が大きなオーバヘッドになってきます。これは、オブジェクトが不要になった
私の印象だと、heap pointerが使えるのにはCopying GCの存在が強く効いています。端的にいえば、GCをやるのだからfree listは要らんと。わざわざGCをやっているのに、加えてO(free listの断片数)(=~O(object数))のcostがかかるfree listの管理をするのは無駄でしょうね。
ただし、これは割り当てしか高速化できません。objectの初期化までは高速化できません(instructionが増える、footprintが削れない)。せめて即値代入で済むようなものぐらいはcacheが使えればなぁ...
Java の場合 new が実行される度にヒープを取りに行くしかありませんから ほとんど逃げようがないです。
Dynix allocatorのように、heapをper-cpuにするのではダメでしょうか? GCがcpu数に比例して重くなってしまいますが...
ちなみに、slab allocatorについてもcacheの同期問題はネックとなるようで、Bonwickはper-cpu cacheなどを将来課題として挙げています。このideaは、現在FreeBSD-currentのmbuf allocatorに実装されています。
初期化の問題は、cacheに入っているobjectはGCの対象外とすれば何とかなりませんか? もちろん、GCの前にcacheから本当に使われていないものを回収する前処理が必要ですが(LRU程度でも十分できそう)。
より多くのコメントがこの議論にあるかもしれませんが、JavaScriptが有効ではない環境を使用している場合、クラシックなコメントシステム(D1)に設定を変更する必要があります。
コンピュータは旧約聖書の神に似ている、規則は多く、慈悲は無い -- Joseph Campbell
Javaの必要性 (スコア:1)
僕はいまいちJavaの良さが分かりません。
誰かJavaのすばらしさを語ってもらえないでしょうか。
Re:Javaの必要性 (スコア:1)
Java Applet のことだったり、 JavaScript のことだったりする
ことがあるので、いっかい問い詰めてみたほうがいいです。
Re:Javaの必要性 (スコア:2, 参考になる)
JITの技術がありますが本質的な解決策では無いと思います。
しかもテキスト処理なんかはJITを使ってもAwkよりもPerlよりも遅い。
次に移植性です。
Write Once Run Anywareとか言っていますがはっきり言って実現されて無いと思います。
移植性 + 速度
で考えるとCの方が上だと思っています。
GCを利点として挙げる人がいますが、それも僕はどうかと思っています。
GCがあるためにむちゃくちゃなプログラムでもある程度動いてしまいます。
1時間ぐらいだったら動くけど長時間動かしているとVMが落ちることがありますし、その時のバ
GCの必要性 (スコア:2, 参考になる)
GC を単にメモリリークを防ぐためのものと考えると大したありがたみはありませんが,メモリフラ
Re:GCの必要性 (スコア:1)
>テーションを防ぐためのものと考えれば,その恩恵は計り知れないと思います。
え?
http://www.is.s.u-tokyo.ac.jp/~vu/jugyo/processor/process/soft/compilerresume/gc/gc.html
>Copying GCの興味深い性質は、コピーするときにオブジェクトの空きをつめるため、fragmentationが発生しないということである。
によると、フラグメンテーションを無くす機能(つーか嬉しい副作用?)を期待できるかどうかは
GCのアルゴリズム次第であって、GC一般の性質ではない、と読めます
Re:GCの必要性 (スコア:1)
> GCのアルゴリズム次第であって、GC一般の性質ではない、と読めますけど?
GC がどのようなアルゴリズムで行われるにせよ、compaction は
行われてるのではないでしょうか? compaction されるというこ
とは、その時点でフラグメンテーションも解消される、ということ
ですよね?違う?
Java の Heap に関しては、激しくオブジェクトの生成/回収を
繰り
Only Jav^Hpanese available :-)
Re:GCの必要性 (スコア:1)
確認ですが、
というのは、異なるサイズのオブジェクトを生成、回収した場合ですか? というのは、同じサイズばっかりだったらそもそも空きメモリの断片化は問題にならないはずなので。
ちなみに、アドレス空間を長持ちさせると(Unixのkernelはその典型)、オブジェクトの生成にともなう再初期化が大きなオーバヘッドになってきます。これは、オブジェクトが不要になった
フリーリストは使わんです (スコア:1)
空き領域の管理をフリーリストではなく、下から順番に詰めて
使って行くヒープポインタ(というのか?)で管理していると思われます。
ヒープポインタを確保したサイズ分増やすだけなので総合的に見てスピードが速いのです。
少なくも SUN JDK1.3、1.
コンタミは発見の母
Re:フリーリストは使わんです (スコア:1)
私の印象だと、heap pointerが使えるのにはCopying GCの存在が強く効いています。端的にいえば、GCをやるのだからfree listは要らんと。わざわざGCをやっているのに、加えてO(free listの断片数)(=~O(object数))のcostがかかるfree listの管理をするのは無駄でしょうね。
ただし、これは割り当てしか高速化できません。objectの初期化までは高速化できません(instructionが増える、footprintが削れない)。せめて即値代入で済むようなものぐらいはcacheが使えればなぁ...
Re:フリーリストは使わんです (スコア:1)
複数のスレッドが free list を手繰るのを防ぐたびに spin lock
するか、OS の同期オブジェクトを使わざるえないです。
これが C/C++ だと、自分のスレッド用にある程度のサイズを
malloc しておいて自前で切り分けて使うことで同期処理の回数を
減らしたり出来ますが、Java の場合 new が実行される度にヒープ
を取りに行くしかありませんから ほとんど逃げようがないです。
> ただし、これは割り当てしか高速化できません。objectの初期化までは高速化できませ
> ん(instructionが増える、footprintが削れない)。せめて即値代入で済むようなものぐらい
> はcacheが使えればなぁ...
VM の実装まで考えると 初期化を飛ばすのはすごく難しいですよ。
昔 考えたのですが 例えば、
class A {
int m1 = 10;
B m2 = new B();
}
の場合、A のメンバにはコンストラクタ内でセットされます。
# m1 = 10; m2 = new B(); のコードはコンストラクタコードに化ける。
A の初期化時にはインスタンスのゼロパディングを省略したい気持ち
になりますが、(1) A のインスタンス生成 → (2) コンストラクタ起動
の間に GC が起きちゃうと m2 の内容にゴミが入っていて access violation
error でダウンです。
結局 Java の言語仕様をきちんと満たす形で実装するためには、
初期化はあんまりサボれないです。
コンタミは発見の母
Re:フリーリストは使わんです (スコア:1)
Dynix allocatorのように、heapをper-cpuにするのではダメでしょうか? GCがcpu数に比例して重くなってしまいますが...
ちなみに、slab allocatorについてもcacheの同期問題はネックとなるようで、Bonwickはper-cpu cacheなどを将来課題として挙げています。このideaは、現在FreeBSD-currentのmbuf allocatorに実装されています。
初期化の問題は、cacheに入っているobjectはGCの対象外とすれば何とかなりませんか? もちろん、GCの前にcacheから本当に使われていないものを回収する前処理が必要ですが(LRU程度でも十分できそう)。
Re:フリーリストは使わんです (スコア:1)
>> ほとんど逃げようがないです。
> Dynix allocatorのように、heapをper-cpuにするのではダメでしょうか? GCがcpu数に
> 比例して重くなってしまいますが...
JavaVM からは OS の挙動は把握しきれないので per-cpu は難しいです。
per-thread でよいのであれば、Thread-Local Heap (TLH と仮に略します)
のアイデア/実装はあります。
ただ、TLH は heap pointer で管理している例しか知りません。
# global heap から固定サイズの領域(chunk) をとってきて TLH とするタイプです。
実際のところ heap pointer を使えば allocater の同期ルーチンって
下のぐらいのコードになっちゃうので、TLH まで持ってきて free list を
使う理由はあまりないのだと思います。
char* old_pointer = NULL;
char* new_pointer = NULL;
do {
old_pointer = ::heap_pointer;
new_pointer = old_pointer + size ;
if( new_pointer >= heap_end ){
// GC
}
} while( compare_and_swap( &::heap_pointer, old_pointer, new_pointer ) );
コンタミは発見の母
続き (スコア:1)
> んか? もちろん、GCの前にcacheから本当に使われていないものを回収する前処理
> が必要ですが(LRU程度でも十分できそう)。
私がオブジェクトの初期化をスキップすることが
難しいと思っている理由なのですが、、、
Java インスタンスはクラスのフィールドの内容を保持している body 部と、
属性情報を保持している header 部に分かれます。
header 部は 実装によりますが、普通 2ワード。多くても4 ワードだと思われます。
header が 2 ワードの場合、
1ワードは所属クラスの情報へのポインタとなっているはずです。
もう1ワードの方には Object.hashCode() で返すハッシュ値や、synchronized で
使うモニタ情報、GC の時に使うマークビットなどが入っている例が多いです。
2ワードのうち再利用できるのはクラス情報へのポインタの 1ワードだけです。
body 部分の再利用はさらに難しいと思われます。
それと、バイトコードレベルでは new とコンストラクタの実行が完全に
分離しているという問題もあります。
Java のソースコード中に
member = new B();
の表記がある場合、
new class B // (1)
dup // (2)
invokespecial B() // (3)
aload 0 (this pointer)
putfield
のようなバイトコードを生成するはずです。
(1) によってヒープからインスタンスが取ってこられるのですが、この時
インスタンスの body 部は zero padding されることが期待されます。
初期値がセットされるのは (3) の中です。
(3) 実行後とメモリイメージが一致する クラス B のインスタンス
があっても、(1) を出たときは body 部が zero padding されている必要があるのです。
コンタミは発見の母