・ visibility:hidden: 非表示にされるが、その領域が空白のまま確保される。
・ display:none: 非表示にされ、その領域も確保されない。
2010年8月1日日曜日
2010年6月15日火曜日
2010年5月29日土曜日
Effective javaまとめ6 ファイナライザを避ける3
ipad発売。
ほしいなぁ・・。
-----------------------------------------------------
Effective javaまとめ6 ファイナライザを避ける3
ファイナイライザの正当な使い方は何かあるか、というとこまで話しました。
正当な使い方は以下の通りです。
■安全ネットとして使う
前回説明した明示的終了メソッドの呼び出しを、オブジェクトの所有者が忘れた場合の「安全ネット」として振舞うことです。
ファイナイライザが即座に実行される保証が無いとはいえ、クライアントが明示的終了メソッドを呼び出すことによる契約の終わりを守りことに失敗した場合に、重要な資源を決して解放しないより、後で解放する方が良いです。
身近な明示的終了メソッドの例として、InputStream, OutputStreamクラスではcloseメソッドが提供されていますが、これらのクラスは、安全ネットとしてのファイナライザを保持しています。
(だからといって、明示的終了メソッドをクライアントが呼び出さないで良いわけではないです。なんども記載していますが、ファイナライザが呼び出されるタイミングは不定であるため、パフォーマンスに悪影響を及ぼすと予想されます)
FileOutputStreamのファイナライザはこんなかんじです。
------------------------------------------------
// ファイルをオープンしているとオブジェクトがはいっているぽいです
private FileDescriptor fd;
protected void finalize() throws IOException {
if (fd != null) {
if (fd == fd.out || fd == fd.err) {
flush();
else {
close();
}
}
------------------------------------------------
■ネイティブピアを回収する。
ネイティブピアとは、通常のオブジェクトがネイティブメソッドを通して委譲を行うネイティブオブジェクトです。
ネイティブピアは通常のオブジェクトではないので、ガーベージコレクタはネイティブピアについて知りませんし、通常のオブジェクトが回収される時に、ネイティブピアを回収することもできません。
ネイティブピアが重要な資源を保持していないと仮定すると、ファイナライザはネイティブピアを回収する処理を行うのに適切な手段です。
さて、ファイナライザに関して注意すべき点を記します。
「ファイナライザ連鎖」は自動的に実行されません。
Object以外のクラスがファイナライザを持ち、サブクラスがそれをオーバーライドしているならば、そのサブクラスのファイナライザはスーパークラスのファイナライザを手作業で呼び出さなければなりません。
tryブロック内でファイナライザを呼び出し、finallyブロック内でスーパークラスのファイナライザを呼び出すべきです。それにより、確実にサブクラスのファイナライザを呼び出すことができます。
サブクラスの実装者がスーパークラスのファイナライザを呼び出すのを忘れた場合、もしくは悪意を持って呼び出すことを行わなかった場合、スーパークラスのファイナライザは絶対に呼び出されません。
上記のような事象を防御するための方法として、ファイナライズを行う必要があるクラスにファイナライザを書く代わりに、エンクロージングインスタンス(内部クラスにとっての外部クラスのインスタンス)をファイナライズする事だけを目的とした無名クラスにファイナライザを書く、という方法が挙げられます。
その無名クラスの1つのインスタンスは、ファイナライザガーディアン(カコイイ!)と呼ばれ、エンクロージングクラスの個々のインスタンスに対して生成されます。
エンクロージングインスタンスは、privateのインスタンスフィールドにそのファイナライザガーディアンへの唯一の参照を保持するようにします。それにより、ファイナライザガーディアンはエンクロージングインスタンスと同時にファイナライズ対象となります。
ガーディアンがファイナライズされる時に、ガーディアンのファイナライザが、エンクロージングクラスに対するメソッドであるかのように、ガーディアンはエンクロージングインスタンスに必要なファイナライズ処理を行います。
ファイナライザガーディアンのイメージ
---------------------------------------------
public class IamAHero {
private final Object finalizeGuardian = new Object() {
protected void finalize() throws Throwable {
// IamAHeroをファイナライズする
}
}
}
---------------------------------------------
この技法は、ファイナライザを持つ全てのfinalではないpublicのクラスに対して検討すべきです。
■まとめ
安全ネット、あるいはネイティブピアオブジェクトを解放する以外の目的でファイナライザを使用するべきではありません。
使用するときは、スーパークラスのファイナライザを呼び出すことを忘れてはいけません。
publicでfinalではないクラスにファイナライザを提供する必要がある場合、ファイナライザガーディアンの使用を検討してください。
----> おわり
ほしいなぁ・・。
-----------------------------------------------------
Effective javaまとめ6 ファイナライザを避ける3
ファイナイライザの正当な使い方は何かあるか、というとこまで話しました。
正当な使い方は以下の通りです。
■安全ネットとして使う
前回説明した明示的終了メソッドの呼び出しを、オブジェクトの所有者が忘れた場合の「安全ネット」として振舞うことです。
ファイナイライザが即座に実行される保証が無いとはいえ、クライアントが明示的終了メソッドを呼び出すことによる契約の終わりを守りことに失敗した場合に、重要な資源を決して解放しないより、後で解放する方が良いです。
身近な明示的終了メソッドの例として、InputStream, OutputStreamクラスではcloseメソッドが提供されていますが、これらのクラスは、安全ネットとしてのファイナライザを保持しています。
(だからといって、明示的終了メソッドをクライアントが呼び出さないで良いわけではないです。なんども記載していますが、ファイナライザが呼び出されるタイミングは不定であるため、パフォーマンスに悪影響を及ぼすと予想されます)
FileOutputStreamのファイナライザはこんなかんじです。
------------------------------------------------
// ファイルをオープンしているとオブジェクトがはいっているぽいです
private FileDescriptor fd;
protected void finalize() throws IOException {
if (fd != null) {
if (fd == fd.out || fd == fd.err) {
flush();
else {
close();
}
}
------------------------------------------------
■ネイティブピアを回収する。
ネイティブピアとは、通常のオブジェクトがネイティブメソッドを通して委譲を行うネイティブオブジェクトです。
ネイティブピアは通常のオブジェクトではないので、ガーベージコレクタはネイティブピアについて知りませんし、通常のオブジェクトが回収される時に、ネイティブピアを回収することもできません。
ネイティブピアが重要な資源を保持していないと仮定すると、ファイナライザはネイティブピアを回収する処理を行うのに適切な手段です。
さて、ファイナライザに関して注意すべき点を記します。
「ファイナライザ連鎖」は自動的に実行されません。
Object以外のクラスがファイナライザを持ち、サブクラスがそれをオーバーライドしているならば、そのサブクラスのファイナライザはスーパークラスのファイナライザを手作業で呼び出さなければなりません。
tryブロック内でファイナライザを呼び出し、finallyブロック内でスーパークラスのファイナライザを呼び出すべきです。それにより、確実にサブクラスのファイナライザを呼び出すことができます。
サブクラスの実装者がスーパークラスのファイナライザを呼び出すのを忘れた場合、もしくは悪意を持って呼び出すことを行わなかった場合、スーパークラスのファイナライザは絶対に呼び出されません。
上記のような事象を防御するための方法として、ファイナライズを行う必要があるクラスにファイナライザを書く代わりに、エンクロージングインスタンス(内部クラスにとっての外部クラスのインスタンス)をファイナライズする事だけを目的とした無名クラスにファイナライザを書く、という方法が挙げられます。
その無名クラスの1つのインスタンスは、ファイナライザガーディアン(カコイイ!)と呼ばれ、エンクロージングクラスの個々のインスタンスに対して生成されます。
エンクロージングインスタンスは、privateのインスタンスフィールドにそのファイナライザガーディアンへの唯一の参照を保持するようにします。それにより、ファイナライザガーディアンはエンクロージングインスタンスと同時にファイナライズ対象となります。
ガーディアンがファイナライズされる時に、ガーディアンのファイナライザが、エンクロージングクラスに対するメソッドであるかのように、ガーディアンはエンクロージングインスタンスに必要なファイナライズ処理を行います。
ファイナライザガーディアンのイメージ
---------------------------------------------
public class IamAHero {
private final Object finalizeGuardian = new Object() {
protected void finalize() throws Throwable {
// IamAHeroをファイナライズする
}
}
}
---------------------------------------------
この技法は、ファイナライザを持つ全てのfinalではないpublicのクラスに対して検討すべきです。
■まとめ
安全ネット、あるいはネイティブピアオブジェクトを解放する以外の目的でファイナライザを使用するべきではありません。
使用するときは、スーパークラスのファイナライザを呼び出すことを忘れてはいけません。
publicでfinalではないクラスにファイナライザを提供する必要がある場合、ファイナライザガーディアンの使用を検討してください。
----> おわり
2010年5月18日火曜日
Effective javaまとめ6 ファイナライザを避ける2
チャリンコを家の中で保管することに成功しますた。
後輪を外すのが意外と簡単で感動した。そしてBBをピカピカにした。
快感・・・
-----------------------------------------------------
■項目6 ファイナライザを避ける2
ファイナライザの使用を避けるべき理由は前回の内容以外にまだあります。
ファイナライズの最中に例外が発生した場合、その例外は無視され、ファイナライズは終了します。
キャッチされなかった例外は、そのオブジェクトを不正な状態のままにする可能性があります。
また、通常、キャッチされなかった例外は、スレッドを終了させスタックトレースを表示しますが。ファイナライザ内ではそのようになりません。ワーニングさえ表示しません。
さて、ファイナライザの使用を控えるべき理由を記載してきましたが、ファイルやスレッドなどの終了を必要とする資源を持っているオブジェクトのクラスに対して、ファイナライザを各代わりに、何をするべきでしょうか。
明示的終了メソッドを提供すべきです。
各インスタンスが必要なくなった時点で、クライアントに明示的終了メソッドを呼び出すことを要求するのです。注意すべき点は、そのインスタンス自身が、「自分は終了した」という事実を保存しておく必要があるという点です。終了した後にオブジェクトが利用された場合、IllegalStateExceptionをスローすべきです。
(APIによると、IllegalStateExceptionは、不正または不適切なときにメソッドが呼び出されたことを示します。)
明示的終了メソッドの典型的な例は、InputStreamやOutputStreamに対するcloseメソッドです。
明示的終了メソッドは、大抵try finallyブロックと伴に利用されます。
finallyブロック内で明示的終了メソッドを呼び出します。
以下の2点がメリットとして挙げられるためです。
・ オブジェクトが必要な範囲をtry finallyブロックで囲むことで、オブジェクトが不要になり次第、迅速に後始末ができる。
・例外が発生しても確実に後始末を行うことが可能
では、ファイナライザが有効なときはどんな時でしょうか・・。
正当な使い方は2つあります。
--> つづーく
後輪を外すのが意外と簡単で感動した。そしてBBをピカピカにした。
快感・・・
-----------------------------------------------------
■項目6 ファイナライザを避ける2
ファイナライザの使用を避けるべき理由は前回の内容以外にまだあります。
ファイナライズの最中に例外が発生した場合、その例外は無視され、ファイナライズは終了します。
キャッチされなかった例外は、そのオブジェクトを不正な状態のままにする可能性があります。
また、通常、キャッチされなかった例外は、スレッドを終了させスタックトレースを表示しますが。ファイナライザ内ではそのようになりません。ワーニングさえ表示しません。
さて、ファイナライザの使用を控えるべき理由を記載してきましたが、ファイルやスレッドなどの終了を必要とする資源を持っているオブジェクトのクラスに対して、ファイナライザを各代わりに、何をするべきでしょうか。
明示的終了メソッドを提供すべきです。
各インスタンスが必要なくなった時点で、クライアントに明示的終了メソッドを呼び出すことを要求するのです。注意すべき点は、そのインスタンス自身が、「自分は終了した」という事実を保存しておく必要があるという点です。終了した後にオブジェクトが利用された場合、IllegalStateExceptionをスローすべきです。
(APIによると、IllegalStateExceptionは、不正または不適切なときにメソッドが呼び出されたことを示します。)
明示的終了メソッドの典型的な例は、InputStreamやOutputStreamに対するcloseメソッドです。
明示的終了メソッドは、大抵try finallyブロックと伴に利用されます。
finallyブロック内で明示的終了メソッドを呼び出します。
以下の2点がメリットとして挙げられるためです。
・ オブジェクトが必要な範囲をtry finallyブロックで囲むことで、オブジェクトが不要になり次第、迅速に後始末ができる。
・例外が発生しても確実に後始末を行うことが可能
では、ファイナライザが有効なときはどんな時でしょうか・・。
正当な使い方は2つあります。
--> つづーく
2010年5月13日木曜日
Effective javaまとめ6 ファイナライザを避ける1
忙しいほど覚醒するパターン
---------------------------------------------------
■項目6 ファイナライザを避ける
ファイナライザには有効な使用方法が多少ありますが、基本的には使用することを避けるべきです。
ファイナライザはC++のデストラクタと違い、呼び出されるタイミングを予測することができません。
デストラクタは、オブジェクトに関連付けられているメモリ領域を回収する通常の方法として利用されます。
javaではオブジェクトが到達不可能な状態になると、ガーベージコレクタにより自動的に関連付けられているメモリ領域が回収されます。
デストラクタは、メモリ以外の資源を回収するためにも使用されます。
javaでは、それらの目的で、try finally ブロックを利用します。
オブイェクトが到達不可能な状態になってからファイナライザがjvmによって実行させるまでの時間は、どれだけの長さにもなりえます。jvm実装ごとに大きく異なっています。
これは、時間的な制約のある事象をファイナライザで行うべきではないことを示してます。
クラスにファイナライザを提供することで、そこクラスのインスタンスの回収が遅れる可能性もあります。
ファイナライザを実行するためのスレッドが、そのアプリケーションの他のスレッドより低い優先順位で動作している場合、オブジェクトがファイナライズ対象となる速さが、オブジェクトがファイナライズされる速度を上回る可能性があります。そうすると、どんどん回収されないメモリ領域が増えていき、最終的にアウトオブメモリーとなる可能性があります。
さらに、ファイナライザは必ず実行されるとは限りません。(javaの言語仕様では、ファイナライザの実行を保証していないためです)結果として、ファイナライザで重要な永続性のある状態を更新するような処理をお行うことは望ましくない、と言えます。
System.gc()やSystem,runFinalizer()は、ファイナライザが実行される可能性を高めるものではありませうが、実行されることを保証するものではありません。System.runFinalizersOnExit()とRuntime.runFinalizeOnExit()は、ファイナライズを保証するらしいです。ただ、致命的な欠陥があるようで、推奨されていません。(どんな欠陥かはなんとなくしか調べなかったので記載しません)
---> 続く
---------------------------------------------------
■項目6 ファイナライザを避ける
ファイナライザには有効な使用方法が多少ありますが、基本的には使用することを避けるべきです。
ファイナライザはC++のデストラクタと違い、呼び出されるタイミングを予測することができません。
デストラクタは、オブジェクトに関連付けられているメモリ領域を回収する通常の方法として利用されます。
javaではオブジェクトが到達不可能な状態になると、ガーベージコレクタにより自動的に関連付けられているメモリ領域が回収されます。
デストラクタは、メモリ以外の資源を回収するためにも使用されます。
javaでは、それらの目的で、try finally ブロックを利用します。
オブイェクトが到達不可能な状態になってからファイナライザがjvmによって実行させるまでの時間は、どれだけの長さにもなりえます。jvm実装ごとに大きく異なっています。
これは、時間的な制約のある事象をファイナライザで行うべきではないことを示してます。
クラスにファイナライザを提供することで、そこクラスのインスタンスの回収が遅れる可能性もあります。
ファイナライザを実行するためのスレッドが、そのアプリケーションの他のスレッドより低い優先順位で動作している場合、オブジェクトがファイナライズ対象となる速さが、オブジェクトがファイナライズされる速度を上回る可能性があります。そうすると、どんどん回収されないメモリ領域が増えていき、最終的にアウトオブメモリーとなる可能性があります。
さらに、ファイナライザは必ず実行されるとは限りません。(javaの言語仕様では、ファイナライザの実行を保証していないためです)結果として、ファイナライザで重要な永続性のある状態を更新するような処理をお行うことは望ましくない、と言えます。
System.gc()やSystem,runFinalizer()は、ファイナライザが実行される可能性を高めるものではありませうが、実行されることを保証するものではありません。System.runFinalizersOnExit()とRuntime.runFinalizeOnExit()は、ファイナライズを保証するらしいです。ただ、致命的な欠陥があるようで、推奨されていません。(どんな欠陥かはなんとなくしか調べなかったので記載しません)
---> 続く
2010年5月11日火曜日
Effective javaまとめ5 廃れたオブジェクト参照を取り除く3
ミッドナイトミートエクスプレスという映画を見ました。
ウェスクレイヴンというホラー映画監督のです。
ほんとーに久々におもろかったでぇ
前回の自分のブログを読んでみましたが、とても意味がわかりにくい・・
自分が理解するより、アウトプットする方が難しいです・・
------------------------------------------------------
■項目5 廃れたオブジェクト参照を取り除く3
前回、意味をなさなくなったキャッシュオブジェクトをガーベージコレクトする方法を1つ記しました。
今回はもう1つの方法を記します。
それは、「オブジェクトをキャッシュしてからある程度の時間が経過したら、そのキャッシュオブジェクトを破棄する」という方法です。
上記は、java.util.Timer APIを使用し、バックグランドのスレッドにより行うこともできますし、java.util.LinkedHashMapのremoveEldestEntryメソッドのように、キャッシュに新たなオブジェクトを追加した際の副作用として実現することもできます。
LinkedHashMapのputメソッドは、自身に新たなエントリを追加する際、removeEldestEntryを呼び出します。
removeEldestEntryがtrueを返した場合、自身のキャッシュに含まれる一番古いオブジェクトを削除します。
removeEldestEntryはデフォルトではfalseを返しますので、オーバーライドし、目的に応じてtrueを返すようにします。javadocでは以下のような実装方法をサンプルとして挙げています。
----------------------------------------------------
private static final int MAX_ENTRIES = 100;
protected boolean removeEldestEntry(Map.Entry eldest) {
return size() > MAX_ENTRIES;
}
----------------------------------------------------
特定のサイズまでキャッシュしたら、以降は古いものから破棄していく、という方法です。
これなら、キャッシュがどんどん肥大していくことは無いです。
--> なんかまとまりませんでしたが、おわりです。
ウェスクレイヴンというホラー映画監督のです。
ほんとーに久々におもろかったでぇ
前回の自分のブログを読んでみましたが、とても意味がわかりにくい・・
自分が理解するより、アウトプットする方が難しいです・・
------------------------------------------------------
■項目5 廃れたオブジェクト参照を取り除く3
前回、意味をなさなくなったキャッシュオブジェクトをガーベージコレクトする方法を1つ記しました。
今回はもう1つの方法を記します。
それは、「オブジェクトをキャッシュしてからある程度の時間が経過したら、そのキャッシュオブジェクトを破棄する」という方法です。
上記は、java.util.Timer APIを使用し、バックグランドのスレッドにより行うこともできますし、java.util.LinkedHashMapのremoveEldestEntryメソッドのように、キャッシュに新たなオブジェクトを追加した際の副作用として実現することもできます。
LinkedHashMapのputメソッドは、自身に新たなエントリを追加する際、removeEldestEntryを呼び出します。
removeEldestEntryがtrueを返した場合、自身のキャッシュに含まれる一番古いオブジェクトを削除します。
removeEldestEntryはデフォルトではfalseを返しますので、オーバーライドし、目的に応じてtrueを返すようにします。javadocでは以下のような実装方法をサンプルとして挙げています。
----------------------------------------------------
private static final int MAX_ENTRIES = 100;
protected boolean removeEldestEntry(Map.Entry eldest) {
return size() > MAX_ENTRIES;
}
----------------------------------------------------
特定のサイズまでキャッシュしたら、以降は古いものから破棄していく、という方法です。
これなら、キャッシュがどんどん肥大していくことは無いです。
--> なんかまとまりませんでしたが、おわりです。
2010年5月8日土曜日
Effective javaまとめ5 廃れたオブジェクト参照を取り除く2
いろいろ忙しい・・。
友達が家の近くに引越してきました。
意外と家賃が安くてショックです。
-----------------------------------------------------
■項目5 廃れたオブジェクト参照を取り除く2
前回、廃れた参照を排除する最善の方法は、その参照が含まれた変数を再利用するか、その変数のスコープ外にでること、という事まで書きました。
現在のjvm実装では、変数が定義されているブロックから抜けるだけでは充分ではなく、参照を消すためには、その変数が含まれるメソッドから抜け出す必要があるので注意が必要です。
では、どのような時に参照にnullを設定するべきでしょうか。
簡単に言えば、前回例として記述したstackのように、プログラマが独自にメモリ管理を行っている場合です。
stackは、配列のある要素が無効になった場合、そのことをガーベージコレクタに知らせるためにnullを設定します。
それ以外、ガーベージコレクタがstackの要素が無効になった事を知る術はありません。つまり、nullを設定しないと、そのメモリは開放されないため、メモリリークの原因となります。
上記以外によくあるメモリリークの原因は、キャッシュです。
オブジェクト参照を一旦キャッシュにいれてしまうと、オブジェクト参照がそこにあることを忘れがちですし、そのオブジェクト参照の意味がなくなったかなり後でも、キャッシュに残したままにしがちです。
この問題に対しては、2つの解決方法があります。
1つは、キャッシュ対象のエントリに対するキーへの参照を、キャッシュ自身以外が保持していることに意味がある場合、そのキャッシュをWeakHashMapで実現することです。
WeakHashMapはキーを弱参照で保持するため、エントリーに対するキーへの参照がキャシュ外に存在しなくなった場合、そのエントリーはガーベージコレクト対象となります。
他のMapはキーを強参照で保持するため、上記のような状態となっても、エントリーはガーベージコレクト対象となりません。
弱参照と強参照の違いは、以下のコードを見るとわかりやすいです。
-----------------------------------------------------------
■ 実験コード
1 Integer key = new Integer(1);
2
3 Map cache = new HashMap(); //キャッシュをHashMapで実装
4 cache.put(key, "entry");
5
6 key = null; //エントリーに対するキー値の参照にnullを設定
7
8 System.gc(); //強制的にGCを実施
9
10 System.out.println(cache.get(new Integer(1)));
-----------------------------------------------------------
実行結果として、「entry」が出力されます。
3行目のキャッシュをWeakHashMapで実装した場合、「null」が出力されます。
6行目でエントリーに対するキーへの参照が存在しなくなるため、紐づくエントリーがガーベージコレクトされたためです。
---> 更に続く・・意外と長い;;
友達が家の近くに引越してきました。
意外と家賃が安くてショックです。
-----------------------------------------------------
■項目5 廃れたオブジェクト参照を取り除く2
前回、廃れた参照を排除する最善の方法は、その参照が含まれた変数を再利用するか、その変数のスコープ外にでること、という事まで書きました。
現在のjvm実装では、変数が定義されているブロックから抜けるだけでは充分ではなく、参照を消すためには、その変数が含まれるメソッドから抜け出す必要があるので注意が必要です。
では、どのような時に参照にnullを設定するべきでしょうか。
簡単に言えば、前回例として記述したstackのように、プログラマが独自にメモリ管理を行っている場合です。
stackは、配列のある要素が無効になった場合、そのことをガーベージコレクタに知らせるためにnullを設定します。
それ以外、ガーベージコレクタがstackの要素が無効になった事を知る術はありません。つまり、nullを設定しないと、そのメモリは開放されないため、メモリリークの原因となります。
上記以外によくあるメモリリークの原因は、キャッシュです。
オブジェクト参照を一旦キャッシュにいれてしまうと、オブジェクト参照がそこにあることを忘れがちですし、そのオブジェクト参照の意味がなくなったかなり後でも、キャッシュに残したままにしがちです。
この問題に対しては、2つの解決方法があります。
1つは、キャッシュ対象のエントリに対するキーへの参照を、キャッシュ自身以外が保持していることに意味がある場合、そのキャッシュをWeakHashMapで実現することです。
WeakHashMapはキーを弱参照で保持するため、エントリーに対するキーへの参照がキャシュ外に存在しなくなった場合、そのエントリーはガーベージコレクト対象となります。
他のMapはキーを強参照で保持するため、上記のような状態となっても、エントリーはガーベージコレクト対象となりません。
弱参照と強参照の違いは、以下のコードを見るとわかりやすいです。
-----------------------------------------------------------
■ 実験コード
1 Integer key = new Integer(1);
2
3 Map cache = new HashMap(); //キャッシュをHashMapで実装
4 cache.put(key, "entry");
5
6 key = null; //エントリーに対するキー値の参照にnullを設定
7
8 System.gc(); //強制的にGCを実施
9
10 System.out.println(cache.get(new Integer(1)));
-----------------------------------------------------------
実行結果として、「entry」が出力されます。
3行目のキャッシュをWeakHashMapで実装した場合、「null」が出力されます。
6行目でエントリーに対するキーへの参照が存在しなくなるため、紐づくエントリーがガーベージコレクトされたためです。
---> 更に続く・・意外と長い;;
2010年5月1日土曜日
Effective javaまとめ5 廃れたオブジェクト参照を取り除く1
京都は良い。
--------------------------------------------------
■項目5 廃れたオブジェクト参照を取り除く
javaはガーベジコレクションを持つ言語であるため、メモリ管理は意識しなくなりがちですが、それは問題があります。
例えば、スタック実装を持つ以下のクラスを見てください。
--------------------------------------------------
public class SampleStack () {
private Object[] stack = new Object[] {};
private int size = 0;
public void push (Object obj) {
stack[size++] = obj;
}
public Object pop () {
return stack[--size];
}
}
--------------------------------------------------
※sizeが0の時popすると落ちますが、例なので気にせずに・・。
このプログラムはメモリリークを抱えています。
どこが問題なのでしょうか。
・・・・。
stackが大きくなった後に小さくなっても、stack自身がそのオブジェクトに対する参照を保持し続ける、という点です。
例えば、pushが10回行われ、popが5回行われたとします。
このとき、stack[5] ~ stack[9]に格納されているオブジェクトは外部のプログラムからアクセスする方法はなくなります。しかし、stack自身は参照を保持し続けているため、これらのオブジェクトはガーベージコレクト対象となりません。
あるオブジェクト参照が保持され続けると、そのオブジェクトが参照しているオブジェクトも回収されず、更にその先も回収されません。
上記に対する解決方法は単純です。
参照が不要になった時点で、参照にnullを設定すれば問題ありません。
改善するとこんな感じです。
--------------------------------------------------
public Object pop () {
stack [--size] = null;
return stack[size];
}
--------------------------------------------------
nullを設定する利点はもう1つあります。
もし使用する意図のない参照を誤って使用した場合、プログラムは間違った挙動をとらず、ヌルポが発生するため、プログラミングエラーを早めに発見するこができる、という点です。
しかし、nullを設定する、という対処方法をいつも採用すれば良いわけではありません。
なぜなら、上記対処はプログラムを不必要に複雑にし、パフォーマンスが低下することも考えられるからです。
最善の方法は、その参照が含まれていた変数を再利用するか、その変数のスコープの外に出ることです。
--> つづく
--------------------------------------------------
■項目5 廃れたオブジェクト参照を取り除く
javaはガーベジコレクションを持つ言語であるため、メモリ管理は意識しなくなりがちですが、それは問題があります。
例えば、スタック実装を持つ以下のクラスを見てください。
--------------------------------------------------
public class SampleStack () {
private Object[] stack = new Object[] {};
private int size = 0;
public void push (Object obj) {
stack[size++] = obj;
}
public Object pop () {
return stack[--size];
}
}
--------------------------------------------------
※sizeが0の時popすると落ちますが、例なので気にせずに・・。
このプログラムはメモリリークを抱えています。
どこが問題なのでしょうか。
・・・・。
stackが大きくなった後に小さくなっても、stack自身がそのオブジェクトに対する参照を保持し続ける、という点です。
例えば、pushが10回行われ、popが5回行われたとします。
このとき、stack[5] ~ stack[9]に格納されているオブジェクトは外部のプログラムからアクセスする方法はなくなります。しかし、stack自身は参照を保持し続けているため、これらのオブジェクトはガーベージコレクト対象となりません。
あるオブジェクト参照が保持され続けると、そのオブジェクトが参照しているオブジェクトも回収されず、更にその先も回収されません。
上記に対する解決方法は単純です。
参照が不要になった時点で、参照にnullを設定すれば問題ありません。
改善するとこんな感じです。
--------------------------------------------------
public Object pop () {
stack [--size] = null;
return stack[size];
}
--------------------------------------------------
nullを設定する利点はもう1つあります。
もし使用する意図のない参照を誤って使用した場合、プログラムは間違った挙動をとらず、ヌルポが発生するため、プログラミングエラーを早めに発見するこができる、という点です。
しかし、nullを設定する、という対処方法をいつも採用すれば良いわけではありません。
なぜなら、上記対処はプログラムを不必要に複雑にし、パフォーマンスが低下することも考えられるからです。
最善の方法は、その参照が含まれていた変数を再利用するか、その変数のスコープの外に出ることです。
--> つづく
2010年4月22日木曜日
Effective javaまとめ4 重複したオブジェクトを生成するのを避ける2
前回の例は、対象となるオブジェクトが初期化後に変更されないため、再利用できることは明白でした。
今回は、アダプターの場合について考えます。
アダプターとは、内部で保持しているオブジェクトに対する代替のインターフェースを提供しながら、その内部で保持しているオブジェクトへの委譲を行っているオブジェクトです。
アダプターは内部で保持しているオブジェクトの状態以外の状態をもっていないため、ある特定のオブジェクトに対するアダプターのインスタンスを2つ以上生成する必要がありません。
MapインターフェースのkeySetメソッドは、そのマップ内の全てのキーから構成されているMapオブジェクトのsetビューを返します。
keySetメソッドの返すsetビューは、なんど呼び出さいても同一のインスタンスを返して問題ありません。
なぜなら、setビューが内包しているMapオブジェクトは、同一のインスタンスであるべきだからです。
setビュー経由で操作したMapオブジェクトの変更は、全てのsetビューで共有されるべきです。
以下はHashMapのkeySetメソッドの実装です。
------------------------------------------------------------
public Set keySet() {
Set ks = keySet;
return (ks != null ? ks : (keySet = new KeySet()));
}
------------------------------------------------------------
HashMapのフィールド変数であるkeySetが初期化されていない場合のみKeySetのインスタンス化を行っています。
本項目は、オブジェクトの生成はコストがかかるため避けるべきである、ということを意味しているわけではありません。
コンストラクタで明示的な処理をしていないオブジェクトの生成はほとんどコストがかかりません。(家マシンでは100万回インスタンス化して、26ms程度)また、オブジェクトをつかいまわすことで、思わぬバグやセキュリティホールを埋め込む可能性があります。また、プログラムの保守性、可読性も低下する可能性があります。
明らかにコストがかかるオブジェクト(DBコネクション生成等)や、複数のオブジェクトを生成することに全く意味が無い場合に、オブジェクトを使いまわすべきです。
--> 終わり
今回は、アダプターの場合について考えます。
アダプターとは、内部で保持しているオブジェクトに対する代替のインターフェースを提供しながら、その内部で保持しているオブジェクトへの委譲を行っているオブジェクトです。
アダプターは内部で保持しているオブジェクトの状態以外の状態をもっていないため、ある特定のオブジェクトに対するアダプターのインスタンスを2つ以上生成する必要がありません。
MapインターフェースのkeySetメソッドは、そのマップ内の全てのキーから構成されているMapオブジェクトのsetビューを返します。
keySetメソッドの返すsetビューは、なんど呼び出さいても同一のインスタンスを返して問題ありません。
なぜなら、setビューが内包しているMapオブジェクトは、同一のインスタンスであるべきだからです。
setビュー経由で操作したMapオブジェクトの変更は、全てのsetビューで共有されるべきです。
以下はHashMapのkeySetメソッドの実装です。
------------------------------------------------------------
public Set keySet() {
Set ks = keySet;
return (ks != null ? ks : (keySet = new KeySet()));
}
------------------------------------------------------------
HashMapのフィールド変数であるkeySetが初期化されていない場合のみKeySetのインスタンス化を行っています。
本項目は、オブジェクトの生成はコストがかかるため避けるべきである、ということを意味しているわけではありません。
コンストラクタで明示的な処理をしていないオブジェクトの生成はほとんどコストがかかりません。(家マシンでは100万回インスタンス化して、26ms程度)また、オブジェクトをつかいまわすことで、思わぬバグやセキュリティホールを埋め込む可能性があります。また、プログラムの保守性、可読性も低下する可能性があります。
明らかにコストがかかるオブジェクト(DBコネクション生成等)や、複数のオブジェクトを生成することに全く意味が無い場合に、オブジェクトを使いまわすべきです。
--> 終わり
2010年4月17日土曜日
Effective javaまとめ4 重複したオブジェクトを生成するのを避ける1
過去のブログを読み返してましたが、日本語が崩壊しているところが多々ありますね・・。
直そうかと思いましたが、めんどーくさいので放置します。ごめんなさい。
---------------------------------------
項目4 重複したオブジェクトを生成するのを避ける
機能的に同じオブジェクトが必要となる都度、新たに生成する代わりに、1つのオブジェクトを再利用することが、大抵の場合適切です。オブジェクトが不変(状態を変更することができない)であれば常に再利用できます。
不変オブジェクトの代表とも言えるStringを利用した以下の例を見てみます。
---------------------------------------
【パターン1】
String s = new String("kows");
---------------------------------------
これは、実行される度に新たなオブジェクトが生成されます。
これを、以下のように変更します。
---------------------------------------
【パターン2】
String s = "kows";
---------------------------------------
これは、実行される度に新たなオブジェクトを生成せず、同一のStringオブジェクトを使いまわします。どちらのコードが効率が良いでしょうか。
---------------------------------------
【パターン1を100万回繰り返す:重複オブジェクトを生成する】
public static void main(String[] args) {
long start = System.currentTimeMillis();
for(int i = 0; i < 1000000; i++) {
String s = new String("mackagy");
}
long end = System.currentTimeMillis();
System.out.println(end - start);
}
結果:409
【パターン2を100万回繰り返す:オブジェクトを使いまわす】
public static void main(String[] args) {
long start = System.currentTimeMillis();
for(int i = 0; i < 1000000; i++) {
String s = "mackagy";
}
long end = System.currentTimeMillis();
System.out.println(end - start);
}
結果:40
---------------------------------------
オブジェクトを使いまわす方が効率が良いみたいです。
※超余談ですが、パターン1を String s = new String() で実行すると、一番遅いです。
String()は、内部で更にchar配列をnewするためです。
不変クラスにはだいたいstaticファクトリーメソッドが提供されています。自分でクラスを設計する場合も提供するべきです。コンストラクタは呼び出される度に新たなオブジェクトを生成しますが、staticファクトリーメソッドは新たなオブジェクトを生成しません。
不変オブジェクトを再利用する以外にも、決して修正されることが分かっている可変オブジェクトを再利用することもできます。
以下の例を見てください
----------------------------------------
【パターン1】
public class Person {
private final Date birthDate;
public Person (Date birthDate) {
this.birthDate = birthDate;
}
public boolean bornAfter2000() {
Calendar base = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
base.set(2000, Calendar.JANUARY, 1, 0, 0, 0);
Date baseDate = base.getTime();
return baseDate.compareTo(birthDate) >= 0;
}
}
----------------------------------------
bornAfter2000メソッド(役割がかなり変ですがあんまり気にしないでください)は呼び出されるごとに、Calendar、Dateオブジェクトを生成します。しかし、これは毎回生成しなくても良いはずです。(必ず2000年1月1日固定となっているため)
これは、以下のように変更することができます。
----------------------------------------
【パターン2】
public class Person {
private final Date birthDate;
private static Date baseDate;
static {
Calendar base = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
base.set(2000, Calendar.JANUARY, 1, 0, 0, 0);
baseDate = base.getTime();
}
public Person (Date birthDate) {
this.birthDate = birthDate;
}
public boolean bornAfter2000() {
return birthDate.compareTo(baseDate) >= 0;
}
}
----------------------------------------
staticイニシャライザは、クラスがロードされた時点で一度だけ実行されるため、不必要にCalendar, Dateオブジェクトが生成されなくなります。
それぞれ100万回実行すると、パターン1は2912ミリ秒かかりますが、パターン2はたった19ミリ秒です。かなり効果があるといえると思います。
ただし、パターン1ではbornAfter2000が呼ばれない限りCalendar,Dateのインスタンスが生成されることはありませんでしたが、パターン2では必ずbornAfter2000を呼び出さなくても、必ずインスタンスが生成されることになります。このへんはちょっと注意が必要です。
---> 続く
直そうかと思いましたが、めんどーくさいので放置します。ごめんなさい。
---------------------------------------
項目4 重複したオブジェクトを生成するのを避ける
機能的に同じオブジェクトが必要となる都度、新たに生成する代わりに、1つのオブジェクトを再利用することが、大抵の場合適切です。オブジェクトが不変(状態を変更することができない)であれば常に再利用できます。
不変オブジェクトの代表とも言えるStringを利用した以下の例を見てみます。
---------------------------------------
【パターン1】
String s = new String("kows");
---------------------------------------
これは、実行される度に新たなオブジェクトが生成されます。
これを、以下のように変更します。
---------------------------------------
【パターン2】
String s = "kows";
---------------------------------------
これは、実行される度に新たなオブジェクトを生成せず、同一のStringオブジェクトを使いまわします。どちらのコードが効率が良いでしょうか。
---------------------------------------
【パターン1を100万回繰り返す:重複オブジェクトを生成する】
public static void main(String[] args) {
long start = System.currentTimeMillis();
for(int i = 0; i < 1000000; i++) {
String s = new String("mackagy");
}
long end = System.currentTimeMillis();
System.out.println(end - start);
}
結果:409
【パターン2を100万回繰り返す:オブジェクトを使いまわす】
public static void main(String[] args) {
long start = System.currentTimeMillis();
for(int i = 0; i < 1000000; i++) {
String s = "mackagy";
}
long end = System.currentTimeMillis();
System.out.println(end - start);
}
結果:40
---------------------------------------
オブジェクトを使いまわす方が効率が良いみたいです。
※超余談ですが、パターン1を String s = new String() で実行すると、一番遅いです。
String()は、内部で更にchar配列をnewするためです。
不変クラスにはだいたいstaticファクトリーメソッドが提供されています。自分でクラスを設計する場合も提供するべきです。コンストラクタは呼び出される度に新たなオブジェクトを生成しますが、staticファクトリーメソッドは新たなオブジェクトを生成しません。
不変オブジェクトを再利用する以外にも、決して修正されることが分かっている可変オブジェクトを再利用することもできます。
以下の例を見てください
----------------------------------------
【パターン1】
public class Person {
private final Date birthDate;
public Person (Date birthDate) {
this.birthDate = birthDate;
}
public boolean bornAfter2000() {
Calendar base = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
base.set(2000, Calendar.JANUARY, 1, 0, 0, 0);
Date baseDate = base.getTime();
return baseDate.compareTo(birthDate) >= 0;
}
}
----------------------------------------
bornAfter2000メソッド(役割がかなり変ですがあんまり気にしないでください)は呼び出されるごとに、Calendar、Dateオブジェクトを生成します。しかし、これは毎回生成しなくても良いはずです。(必ず2000年1月1日固定となっているため)
これは、以下のように変更することができます。
----------------------------------------
【パターン2】
public class Person {
private final Date birthDate;
private static Date baseDate;
static {
Calendar base = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
base.set(2000, Calendar.JANUARY, 1, 0, 0, 0);
baseDate = base.getTime();
}
public Person (Date birthDate) {
this.birthDate = birthDate;
}
public boolean bornAfter2000() {
return birthDate.compareTo(baseDate) >= 0;
}
}
----------------------------------------
staticイニシャライザは、クラスがロードされた時点で一度だけ実行されるため、不必要にCalendar, Dateオブジェクトが生成されなくなります。
それぞれ100万回実行すると、パターン1は2912ミリ秒かかりますが、パターン2はたった19ミリ秒です。かなり効果があるといえると思います。
ただし、パターン1ではbornAfter2000が呼ばれない限りCalendar,Dateのインスタンスが生成されることはありませんでしたが、パターン2では必ずbornAfter2000を呼び出さなくても、必ずインスタンスが生成されることになります。このへんはちょっと注意が必要です。
---> 続く
2010年4月12日月曜日
Effective javaまとめ3 インスタンス化不可能を強制
FFくりーちゃーず2が6末に発売。待ちきれません。
http://www.amiami.com/shop/ProductInfo/product_id/158244/
今回のシークレットはなんだろうか・・・
------------------------------------------------------------
項目3 privateのコンストラクタでインスタンス化不可能を強制する
staticなメソッドとstaticなフィールドだけからなるクラスを作成するケースとして、
java.lang.Math、java.util.Arrays、java.Util.Collectionsのようなユーティリティクラスを作成する場合が挙げられます。
こういったクラスはインスタンス化する設計にはなっていません。(インスタンス化するメリットや意味がありません)しかし、明示的にコンストラクタを定義していない場合、コンパイラはpublicでパラメータ無しのデフォルトコンストラクタを提供します。つまり、インスタンス化するためのクラスではないのにインスタンス化が可能になってしまいます。
クラスを抽象化することでインスタンス化不可能を実現しようとしてもうまくいきません。そのクラスのサブクラスでインスタンス化可能とすることができるためです。更に、継承させるために設計されていると使用者に誤解を与えます。
そこで、ベストな方法としてprivateなコンストラクタを定義する、という方法があります。
public class BearBrick {
private BearBrick() {}
}
「インスタンス化させたくない!」という意図をコメントしておくと親切です。
注意点として、privateなコンストラクタのみを保持するクラスはサブクラスが作成できません。
明示的、あるいは暗黙的に、すべてのコンストラクタはアクセス可能なスーパークラスのコンストラクタを呼び出さなければならないためです。
------------------------------------------------------------
参考に・・・
------------------------------------------------------------
java.lang.Math
------------------------------------------------------------
public final strictfp class Math {
/**
* Don't let anyone instantiate this class.
*/
private Math() {}
------------------------------------------------------------
------------------------------------------------------------
java.util.Arrays
------------------------------------------------------------
public class Arrays {
// Suppresses default constructor, ensuring non-instantiability.
private Arrays() {
}
------------------------------------------------------------
本ではユーティリティクラスに対して言及してましたが、全章でもあったように、シングルトンとして設計されたクラスでもprivateコンストラクタは使用しますですね。
どうでもえーですが、Mathのコンストラクタはprivateなのにjavadeoc形式なんですね。僕もMath派な人です。
http://www.amiami.com/shop/ProductInfo/product_id/158244/
今回のシークレットはなんだろうか・・・
------------------------------------------------------------
項目3 privateのコンストラクタでインスタンス化不可能を強制する
staticなメソッドとstaticなフィールドだけからなるクラスを作成するケースとして、
java.lang.Math、java.util.Arrays、java.Util.Collectionsのようなユーティリティクラスを作成する場合が挙げられます。
こういったクラスはインスタンス化する設計にはなっていません。(インスタンス化するメリットや意味がありません)しかし、明示的にコンストラクタを定義していない場合、コンパイラはpublicでパラメータ無しのデフォルトコンストラクタを提供します。つまり、インスタンス化するためのクラスではないのにインスタンス化が可能になってしまいます。
クラスを抽象化することでインスタンス化不可能を実現しようとしてもうまくいきません。そのクラスのサブクラスでインスタンス化可能とすることができるためです。更に、継承させるために設計されていると使用者に誤解を与えます。
そこで、ベストな方法としてprivateなコンストラクタを定義する、という方法があります。
public class BearBrick {
private BearBrick() {}
}
「インスタンス化させたくない!」という意図をコメントしておくと親切です。
注意点として、privateなコンストラクタのみを保持するクラスはサブクラスが作成できません。
明示的、あるいは暗黙的に、すべてのコンストラクタはアクセス可能なスーパークラスのコンストラクタを呼び出さなければならないためです。
------------------------------------------------------------
参考に・・・
------------------------------------------------------------
java.lang.Math
------------------------------------------------------------
public final strictfp class Math {
/**
* Don't let anyone instantiate this class.
*/
private Math() {}
------------------------------------------------------------
------------------------------------------------------------
java.util.Arrays
------------------------------------------------------------
public class Arrays {
// Suppresses default constructor, ensuring non-instantiability.
private Arrays() {
}
------------------------------------------------------------
本ではユーティリティクラスに対して言及してましたが、全章でもあったように、シングルトンとして設計されたクラスでもprivateコンストラクタは使用しますですね。
どうでもえーですが、Mathのコンストラクタはprivateなのにjavadeoc形式なんですね。僕もMath派な人です。
2010年4月9日金曜日
oracle データベースバッファキャッシュ2
食中毒になった。色々出てしまった・・。あんなに辛かったのは小6の時に40度の熱が出て以来だ。
来週の水曜の勉強会のために調べた内容を一部公開!
----------------------------------------------------------
■ データベースバッファキャッシュの構成
----------------------------------------------------------
データベースバッファキャッシュは以下の2つのリストで管理されています。
・ 書き込みリスト
・ LRUリスト
書き込みリストは使用済みバッファを保持します。
使用済みバッファとは、「修正されたが、まだディスクに書き込まれていないデータを含むバッファ」を指します。
LRUリストは、使用可能バッファ、使用中バッファおよび書込みリストに移動していない使用済バッファを保持します。
使用可能バッファとは、空、もしくはデータファイルと同期がとれているブロックが含まれるバッファを指します。
使用中バッファとは、現在アクセスされているバッファを指します。
LRUリストに含まれる使用済みバッファは特定のタイミングで書き込みリストへ移動します。
LRUリストにはLRU側とMRU側が存在し、LRU側であるほど、そのバッファに含まれるブロックの要求頻度が低く、
MRU側であるほど、そのバッファに含まれるブロックの要求頻度が高いことを表します。
----------------------------------------------------------
■ データベースバッファキャッシュの仕組み
----------------------------------------------------------
ユーザープロセスからデータの要求があると、まず、サーバープロセスは、データベースバッファキャッシュ内のデータを検索します。
キャッシュ内にデータが見つかった場合(キャッシュヒット)、プロセスは、キャッシュからデータを返します。
キャッシュヒットが発生すると、そのブロックは、LRUリストのMRU側へ移動します。
さらに多くのバッファがMRU側へ移動されるにつれて、アクセスが古いバッファはLRU側へ移動していきます。
(使用頻度の低いバッファほどLRU側へ移動しやすいです)
キャッシュ内にデータが見つからなかった場合(キャッシュミス)、
プロセスはディスク上のデータファイルからキャッシュ内のバッファにデータブロックをコピーする必要があります。
データブロックをコピーするには、コピーしたブロックを保持するためのバッファ(使用可能バッファ)を見つける必要があります。
その際、プロセスはLRUリストのLRU側から使用可能バッファの検索を行います。
検索は、以下の何れかの条件を満たすまで続きます。
・ 使用可能バッファを見つける
・ 検索したバッファ数が制限閾値に達する
LRUリスト検索時に使用済みバッファを見つけた場合、そのバッファを書き込みリストへ移動してから検索を続けます。
この際、書き込みリストのサイズが閾値を越えると、書き込みリスト上の使用済みバッファがDBWRによってディスクに書き込まれます。
使用可能バッファが見つかると、プロセスはディスクからバッファにデータブロックを読み込んで、バッファをLRUリストのMRU側へ移動します ※1
使用可能バッファが見つからず、検索したバッファ数が制限しきい値に達すると、プロセスはLRUリストの検索を停止し、データベースライターに使用済みバッファをデータファイルに書き込むよう指示します。
この際、使用済みバッファの書き込みリストへの移動は発生せず、直接LRUリストからディスクへの書き込みが行われます。
こうすることで、使用可能バッファを確保し、そこにデータブロックを読み込みます。
※1
厳密には、インデックススキャンによるランダムリードが実施された場合はMRU側とLRU側の境目にあるコールドポインタという位置に挿入されます。
フルスキャンによるシーケンシャルリードが実施された場合はLRU側に挿入され、次の瞬間には破棄される状態となります。
こういった仕組みにより、本当に重要なデータがLRUリストから押し出されることを防ぎます。
-------------------------------------------------------------------------------------
実際は図もいれてるからもっとわかりやすいだよ!でも掲載の仕方が分からない。みんなすごいなー
あと、まえの投稿でデータベースバッファキャッシュのキャッシュを消す方法を書いたけど、正確にsqlの性能を調べるには、ディクショナリキャッシュ、ライブラリキャッシュの情報も消す必要があるはずなので、以下のコマンドも実行したほうが良い気がしてきた。
ALTER SYSTEM FLUSH SHARED_POOL
(共有プールのクリア)
本番環境で・・(略
来週の水曜の勉強会のために調べた内容を一部公開!
----------------------------------------------------------
■ データベースバッファキャッシュの構成
----------------------------------------------------------
データベースバッファキャッシュは以下の2つのリストで管理されています。
・ 書き込みリスト
・ LRUリスト
書き込みリストは使用済みバッファを保持します。
使用済みバッファとは、「修正されたが、まだディスクに書き込まれていないデータを含むバッファ」を指します。
LRUリストは、使用可能バッファ、使用中バッファおよび書込みリストに移動していない使用済バッファを保持します。
使用可能バッファとは、空、もしくはデータファイルと同期がとれているブロックが含まれるバッファを指します。
使用中バッファとは、現在アクセスされているバッファを指します。
LRUリストに含まれる使用済みバッファは特定のタイミングで書き込みリストへ移動します。
LRUリストにはLRU側とMRU側が存在し、LRU側であるほど、そのバッファに含まれるブロックの要求頻度が低く、
MRU側であるほど、そのバッファに含まれるブロックの要求頻度が高いことを表します。
----------------------------------------------------------
■ データベースバッファキャッシュの仕組み
----------------------------------------------------------
ユーザープロセスからデータの要求があると、まず、サーバープロセスは、データベースバッファキャッシュ内のデータを検索します。
キャッシュ内にデータが見つかった場合(キャッシュヒット)、プロセスは、キャッシュからデータを返します。
キャッシュヒットが発生すると、そのブロックは、LRUリストのMRU側へ移動します。
さらに多くのバッファがMRU側へ移動されるにつれて、アクセスが古いバッファはLRU側へ移動していきます。
(使用頻度の低いバッファほどLRU側へ移動しやすいです)
キャッシュ内にデータが見つからなかった場合(キャッシュミス)、
プロセスはディスク上のデータファイルからキャッシュ内のバッファにデータブロックをコピーする必要があります。
データブロックをコピーするには、コピーしたブロックを保持するためのバッファ(使用可能バッファ)を見つける必要があります。
その際、プロセスはLRUリストのLRU側から使用可能バッファの検索を行います。
検索は、以下の何れかの条件を満たすまで続きます。
・ 使用可能バッファを見つける
・ 検索したバッファ数が制限閾値に達する
LRUリスト検索時に使用済みバッファを見つけた場合、そのバッファを書き込みリストへ移動してから検索を続けます。
この際、書き込みリストのサイズが閾値を越えると、書き込みリスト上の使用済みバッファがDBWRによってディスクに書き込まれます。
使用可能バッファが見つかると、プロセスはディスクからバッファにデータブロックを読み込んで、バッファをLRUリストのMRU側へ移動します ※1
使用可能バッファが見つからず、検索したバッファ数が制限しきい値に達すると、プロセスはLRUリストの検索を停止し、データベースライターに使用済みバッファをデータファイルに書き込むよう指示します。
この際、使用済みバッファの書き込みリストへの移動は発生せず、直接LRUリストからディスクへの書き込みが行われます。
こうすることで、使用可能バッファを確保し、そこにデータブロックを読み込みます。
※1
厳密には、インデックススキャンによるランダムリードが実施された場合はMRU側とLRU側の境目にあるコールドポインタという位置に挿入されます。
フルスキャンによるシーケンシャルリードが実施された場合はLRU側に挿入され、次の瞬間には破棄される状態となります。
こういった仕組みにより、本当に重要なデータがLRUリストから押し出されることを防ぎます。
-------------------------------------------------------------------------------------
実際は図もいれてるからもっとわかりやすいだよ!でも掲載の仕方が分からない。みんなすごいなー
あと、まえの投稿でデータベースバッファキャッシュのキャッシュを消す方法を書いたけど、正確にsqlの性能を調べるには、ディクショナリキャッシュ、ライブラリキャッシュの情報も消す必要があるはずなので、以下のコマンドも実行したほうが良い気がしてきた。
ALTER SYSTEM FLUSH SHARED_POOL
(共有プールのクリア)
本番環境で・・(略
2010年4月5日月曜日
oracle データベースバッファキャッシュ1
来週の水曜にプロジェクトで実施してる勉強会の発表があるので、えふぇくちぶjavaが停止中。
ブログの更新を止めたくないのでjava意外の話題で更新してみます。
---- oracle データベースバッファキャッシュについて ----
データベースバッファキャッシュとは、ディスク(データファイル)への書き込み、読み込みを減らす(ディスクI/Oの低減)目的で使用されるメモリ領域。
ユーザープロセスからデータの要求があると、まず、サーバープロセスは、データベースバッファキャッシュ内のデータを検索する。
キャッシュ内にデータが見つかった場合(キャッシュヒット)、サーバープロセスは、データをメモリから直接読み取ることができる。
キャッシュ内にデータが見つからなかった場合(キャッシュミス)、プロセスはデータにアクセスする前に、 ディスク上のデータファイルからキャッシュ内のバッファにデータブロックをコピーする必要がある。
キャッシュヒットによるデータのアクセスは、ディスクI/Oが発生しないため、キャッシュミスによるデータのアクセスよりも高速。
SQLの性能を調べてる時とか、キャッシュをクリアしないと正確な実行時間がわからないので注意。
ALTER SYSTEM FLUSH BUFFER_CACHE
SQLの性能を調べてる時とか、キャッシュをクリアしないと正確な実行時間がわからないので注意。
ALTER SYSTEM FLUSH BUFFER_CACHE
でデータベースバッファキャッシュがクリアされまする。(10gから)
9iの場合はインスタンス停止が必要らしい。ふべんだね!
注意:データベースバッファキャッシュは全てのプロセスで共有されているため、本番環境とかでやると死ねます。
2010年3月31日水曜日
Effective javaまとめ2 シングルトーーン
シングルトンは、一度しかインスタンスが作成されないクラスである。
通常、システムとして本質的に1つか存在し得ない事象を表すための使用する。
シングルトンを実装するには2つの方法がある。
1.コンストラクタをprivateとし、そのクラスのインスタンスへのアクセスは、public static finalなメンバーを提供する。
public class Mackagy {
public static final Mackagy INSTANCE = new Mackagy();
private Mackagy() {
.....
}
}
privateなコンストラクタのみを提供することで、Mackagyのインスタンスは常に1つしか存在しないことを保証する。
2.コンストラクタをprivateとし、publicなstaticファクトリーメソッドを提供する。
public class Mackagy {
private static final Mackagy INSTANCE = new Mackagy();
privte Mackagy () {
....
}
public static Mackagy getInstance() {
return INSTANCE;
}
}
1つめの方法の長所は、クラスを構成しているメンバーの宣言から、そのクラスがシングルトンであることが明確であること。(public staticなフィールドがfinalなので、そのフィールドは常に同一のオブジェクト参照を保持する)
2つめの方法の長所は、APIを変更することなく、そのクラスがシングルトンであるべきかどうかを変更できる柔軟性があること。
したがって、そのクラスが永久にシングルトンであることを確信できるのであれば方法1、確信がないのであれば方法2を使用するべき。
→ おわり
2010年3月28日日曜日
Effective javaまとめ1 staticファクトリメソッド2
Effective java P5~P9
項目1 コンストラクタの代わりにstaticファクトリーメソッドの提供を検討する
----->前回からの続き
staticファクトリーメソッドのメリット
3:戻り値型を定義することができる
つまり、戻り値型のサブタイプのオブジェクトを返すことが可能である。
これは、以下の特徴を持つ。
●staticファクトリーメソッドが作成された段階で、実際に返すクラスが未作成でも問題が無い
(戻り値型のサブクラスや実装クラスをあとで作成し、切り替えることが可能)
●受け取ったパラメータに応じて、別々のクラスのインスタンスを返すことが可能
●返すインスタンスのクラスをpublicにする必要がない
(親クラス、またはIFがpublicであれば、返すクラス自身はprivateで問題が無い)
→java.util.Collectionsクラスがこれを実践している
メリットを挙げてきたが、デメリットは以下の通り。
1.隠蔽されたクラスや、privteなコンストラクタしか持たないクラスは、拡張することができない
これはコンポジションを使うことで回避可能
2.他のstaticメソッドと区別がつきにくい
コンストラクタはAPIドキュメンテーションにおいて目立が、staticファクトリーメソッドは目立たないため、そのクラスのインスタンス化方法を知ることが困難になる場合がある。
これは、一般的な命名規則に基づいてメソッド名をつけることで軽減できる。
(valueOf、 geInstanceなど)
最後に、staticファクトリーメソッドを使う強い理由がない場合、コンストラクタを提供するべき。
なぜなら、それが通常の方法だから。
---> おわり
2010年3月26日金曜日
Effective javaまとめ1 staticファクトリメソッド1
Effective java P5~P9
項目1 コンストラクタの代わりにstaticファクトリーメソッドの提供を検討する
クランスのインスタンスを取得する方法として、通常はコンストラクタを提供するが、publicなstaticファクトリーメソッドを提供することもできる。
staticファクトリーメソッドとは、そのクラスのインスタンスを返す単なるstaticメソッドである。
例)Booleanクラスで提供されているstaticファクトリメソッド
public static Boolean valueOf(boolean b) {
return (b ? Boolean.TRUE : Boolean.FALSE);
}
staticファクトリーメソッドの長所は以下の通り。
1:名前を持つことが出来る
コンストラクタと違い、自由に名前をつけることが可能なため、そのメソッドの返すインスタンスの特性をメソッド名として表現することができる。
→ ファクトリーメソッドを持つクラスの使用が用意になる。クライアントのコードの可読性が上がる。
また、オーバーロードの制約も気にする必要がない(名前をつけられるから)
2:メソッドが呼び出されるごとに新しいインスタンスを生成する必要が無い
ファクトリーメソッドで、予め生成された不変クラスのインスタンスを返すようにすることで、不必要な重複したオブジェクトの生成を回避することができる。
つまり、繰り返し呼び出しを行われても、返されるインスタンスは常に同一、ということを保証することができる。(オブジェクトの同一性の比較にequalsメソッドではなく==が使用可能)
3:戻り値型を定義することができる
つまり、戻り値型のサブタイプのオブジェクトを返すことが可能である。
-----> 疲れたので 続く
2010年3月17日水曜日
Oracle DAB1 Silver 10g
今更ながらOracle DBA1 silver 10g 受けてきました。
なぜ11gじゃなくて10gなのかは秘密です。
数年前に9iのsilverを取得したときは、あんまりためになったとは思わなかったんですが、ある程度業務でoracleを使った今、試験勉強してみとぜんぜん理解度が違います。
かなりためになりました。ふつーに業務で活かせる雰囲気です。
ということで、試験勉強して重要だなーと思った箇所とか、もっと深く掘り下げたいと感じた部分をまとめていこうと思います。
登録:
投稿 (Atom)