Java: 2008年5月アーカイブ

急にEclipseが起動しなくなった。

なんか、こんなエラーログ吐かれちゃってまいった。

#
# An unexpected error has been detected by Java Runtime Environment:
#
# EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x381f7bfc, pid=3824, tid=1304
#
# Java VM: Java HotSpot(TM) Client VM (10.0-b22 mixed mode windows-x86)
# Problematic frame:
# C [libapr-1.dll+0x7bfc]
#
# If you would like to submit a bug report, please visit:
# http://java.sun.com/webapps/bugreport/crash.jsp
# The crash happened outside the Java Virtual Machine in native code.
# See problematic frame for where to report the bug.
#

~中略~
Heap
def new generation total 118016K, used 38032K [0x03290000, 0x0b290000, 0x0b290000)
eden space 104960K, 23% used [0x03290000, 0x04af4270, 0x09910000)
from space 13056K, 100% used [0x0a5d0000, 0x0b290000, 0x0b290000)
to space 13056K, 0% used [0x09910000, 0x09910000, 0x0a5d0000)
tenured generation total 393216K, used 4410K [0x0b290000, 0x23290000, 0x23290000)
the space 393216K, 1% used [0x0b290000, 0x0b6debf0, 0x0b6dec00, 0x23290000)
compacting perm gen total 65536K, used 26567K [0x23290000, 0x27290000, 0x33290000)
the space 65536K, 40% used [0x23290000, 0x24c81c98, 0x24c81e00, 0x27290000)
No shared spaces configured.

Dynamic libraries:
0x00400000 - 0x0040e000 C:\Eclipse\eclipse3.3.2_ruby\eclipse.exe
0x7c940000 - 0x7c9dd000 C:\WINDOWS\system32\ntdll.dll
0x7c800000 - 0x7c932000 C:\WINDOWS\system32\kernel32.dll
0x77cf0000 - 0x77d7f000 C:\WINDOWS\system32\USER32.dll
0x77ed0000 - 0x77f17000 C:\WINDOWS\system32\GDI32.dll
0x5ab60000 - 0x5abfa000 C:\WINDOWS\system32\COMCTL32.dll
0x77d80000 - 0x77e29000 C:\WINDOWS\system32\ADVAPI32.dll
0x77e30000 - 0x77ec2000 C:\WINDOWS\system32\RPCRT4.dll
0x77fa0000 - 0x77fb1000 C:\WINDOWS\system32\Secur32.dll
0x77bc0000 - 0x77c18000 C:\WINDOWS\system32\MSVCRT.dll
0x762e0000 - 0x762fd000 C:\WINDOWS\system32\IMM32.DLL
0x60740000 - 0x60749000 C:\WINDOWS\system32\LPK.DLL
0x73f80000 - 0x73feb000 C:\WINDOWS\system32\USP10.dll
0x72000000 - 0x72012000 C:\Eclipse\eclipse3.3.2_ruby\
plugins\org.eclipse.equinox.launcher.win32.win32.x86_
1.0.3.R33x_v20080118\eclipse_1023.dll
0x77bb0000 - 0x77bb8000 C:\WINDOWS\system32\VERSION.dll
0x58730000 - 0x58768000 C:\WINDOWS\system32\uxtheme.dll
0x74660000 - 0x746ab000 C:\WINDOWS\system32\MSCTF.dll
0x76d90000 - 0x76db2000 C:\WINDOWS\system32\apphelp.dll
0x73620000 - 0x7364e000 C:\WINDOWS\system32\msctfime.ime
0x76970000 - 0x76aad000 C:\WINDOWS\system32\ole32.dll
0x3a600000 - 0x3a677000 C:\WINDOWS\system32\imjp9.ime
0x7d5b0000 - 0x7ddb0000 C:\WINDOWS\system32\SHELL32.dll
0x77f20000 - 0x77f96000 C:\WINDOWS\system32\SHLWAPI.dll
0x3a690000 - 0x3a761000 C:\WINDOWS\system32\imjp9k.dll
0x770d0000 - 0x7715b000 C:\WINDOWS\system32\OLEAUT32.dll
0x77160000 - 0x77263000 C:\WINDOWS\WinSxS\x86_Microsoft.Windows.Common-Controls_6595b64144ccf1df_6.0.2600.2982_x-ww_ac3f9c03\comctl32.dll
0x6d7c0000 - 0x6da10000 C:\Program Files\Java\jre1.6.0_06
\bin\client\jvm.dll
0x76af0000 - 0x76b1b000 C:\WINDOWS\system32\WINMM.dll
0x7c340000 - 0x7c396000 C:\WINDOWS\system32\MSVCR71.dll
0x6d270000 - 0x6d278000 C:\Program Files\Java\jre1.6.0_06
\bin\hpi.dll
0x76ba0000 - 0x76bab000 C:\WINDOWS\system32\PSAPI.DLL
0x6d770000 - 0x6d77c000 C:\Program Files\Java\jre1.6.0_06
\bin\verify.dll
0x6d310000 - 0x6d32f000 C:\Program Files\Java\jre1.6.0_06
\bin\java.dll
0x6d7b0000 - 0x6d7bf000 C:\Program Files\Java\jre1.6.0_06
\bin\zip.dll
0x6d570000 - 0x6d583000 C:\Program Files\Java\jre1.6.0_06
\bin\net.dll
0x719e0000 - 0x719f7000 C:\WINDOWS\system32\WS2_32.dll
0x719d0000 - 0x719d8000 C:\WINDOWS\system32\WS2HELP.dll
0x6d590000 - 0x6d599000 C:\Program Files\Java\jre1.6.0_06
\bin\nio.dll
0x360d0000 - 0x3611f000 C:\Eclipse\eclipse3.3.2_ruby\configuration\
org.eclipse.osgi\bundles\115\1\.cp\swt-win32-3349.dll
0x76300000 - 0x76348000 C:\WINDOWS\system32\comdlg32.dll
0x76660000 - 0x76708000 C:\WINDOWS\system32\WININET.dll
0x765c0000 - 0x76653000 C:\WINDOWS\system32\CRYPT32.dll
0x77c40000 - 0x77c52000 C:\WINDOWS\system32\MSASN1.dll
0x01220000 - 0x01228000 C:\Eclipse\eclipse3.3.2_ruby\configuration\
org.eclipse.osgi\bundles\26\1\.cp\os\win32\x86\localfile_1_0_0.dll
0x74bc0000 - 0x74bec000 C:\WINDOWS\system32\oleacc.dll
0x75fd0000 - 0x76035000 C:\WINDOWS\system32\MSVCP60.dll
0x36670000 - 0x36684000 C:\Eclipse\eclipse3.3.2_ruby\configuration\
org.eclipse.osgi\bundles\115\1\.cp\swt-gdip-win32-3349.dll
0x4af10000 - 0x4b0b3000 C:\WINDOWS\WinSxS\x86_Microsoft.Windows.GdiPlus_
6595b64144ccf1df_1.0.2600.2180_x-ww_522f9f82\gdiplus.dll
0x37220000 - 0x37780000 C:\WINDOWS\system32\xpsp2res.dll
0x6eec0000 - 0x6eee1000 C:\Eclipse\eclipse3.3.2_ruby\plugins\org.tigris.
subversion.javahl.win32_1.0.0\libapr.dll
0x71980000 - 0x719bf000 C:\WINDOWS\system32\MSWSOCK.dll
0x6ee50000 - 0x6ee59000 C:\Eclipse\eclipse3.3.2_ruby\plugins\org.tigris.
subversion.javahl.win32_1.0.0\libapriconv.dll
0x37ec0000 - 0x37fc6000 C:\Eclipse\eclipse3.3.2_ruby\plugins\org.tigris.
subversion.javahl.win32_1.0.0\libeay32.dll
0x71a00000 - 0x71a0b000 C:\WINDOWS\system32\WSOCK32.dll
0x37fd0000 - 0x3807d000 C:\Eclipse\eclipse3.3.2_ruby\plugins\org.tigris.
subversion.javahl.win32_1.0.0\libdb43.dll
0x38080000 - 0x380b2000 C:\Eclipse\eclipse3.3.2_ruby\plugins\org.tigris.
subversion.javahl.win32_1.0.0\ssleay32.dll
0x6ee60000 - 0x6ee89000 C:\Eclipse\eclipse3.3.2_ruby\plugins\org.tigris.
subversion.javahl.win32_1.0.0\libaprutil.dll
0x380c0000 - 0x380d2000 C:\Eclipse\eclipse3.3.2_ruby\plugins\org.tigris.
subversion.javahl.win32_1.0.0\intl3_svn.dll
0x380e0000 - 0x381d8000 C:\Eclipse\eclipse3.3.2_ruby\plugins\org.tigris.
subversion.javahl.win32_1.0.0\libsvnjavahl-1.dll
0x76730000 - 0x76739000 C:\WINDOWS\system32\SHFOLDER.dll
0x6ee40000 - 0x6ee45000 C:\Program Files\Subversion\iconv\_tbl_simple.so
0x381e0000 - 0x381e9000 C:\Program Files\Subversion\bin\libapriconv-1.dll
0x381f0000 - 0x38210000 C:\Program Files\Subversion\bin\libapr-1.dll

VM Arguments:
jvm_args: -Dosgi.requiredJavaVersion=1.6 -Xms512m -Xmx512m -XX:NewSize=128m -XX:MaxNewSize=128m -XX:PermSize=64m -XX:MaxPermSize64m -XX:MaxPermSize=256M
java_command:
Launcher Type: generic

~後略~


初めは、EXCEPTION_ACCESS_VIOLATION (0xc0000005) でググって、ヒープの設定とかかな、と思っていろいろいじってみたが改善しない。

で、↓のメッセージに気づいてググリ直した。
# C [libapr-1.dll+0x7bfc]

http://yujiwen2006.spaces.live.com/default.aspx?mkt=ja-JP&partner=Live.Spaces
この方のおかげで何とかなりました。ありがとうございます。

インストールされてたSubversionのPathを消したら起動しました。
でも、なんで急に起動しなくなったんだろう。。。

とある理由により、以前、DerbyとかMySQLのIDENTITY的なカラムのHibernateのアノテーションでやったものとまったく同じ処理をPostgreSQLでやってみた。

基本的にはDerbyとかMySQLのIDENTITY的なカラムのHibernateのアノテーションと変わらないノリでやるんだけど、PostgreSQLはauto-incrementがないからOracleとかと同じくSequenceを使う。そうするとアノテーションの記述がちょっと変わってくる。

■auto-increment(MySQLとかDerbyとか)の場合
==============
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "ID", unique = true, nullable = false)
public long getId() {
return this.id;
}
==============

■Sequence(PostgreSQLとかOracle)の場合
==============
@Id @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="hoge_seq")
@SequenceGenerator(name="hoge_seq", sequenceName="hoge_seq")
@Column(name = "id", unique = true, nullable = false)
public int getId() {
return this.id;
}
==============

実際にDB上に作ったSequenceを@SequenceGeneratorのsequenctNameに書く。
@GenerationValueのgeneratorはたぶんテキトーでいい。@SequenceGeneratorのnameと同じにしときゃいいんだと思う。ちょっと試したらいいんだろうけど、1分後には寝るので各自で試してください。筆者はめんどくさいから、実SEQと同じにしておいた。

以上、よろしくお願いいたします。

Hibernateのログを出したかったら、log4j.propertiesに以下の記述を入れる。

=============
log4j.logger.org.hibernate=DEBUG
=============

Hibernateはcommon-loggingを使っているので、アプリがLog4J使っていればLog4Jの出力IFが使われる。

DEBUGとかだと、ちょー出ますよ。


こんな感じ。

==============
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "ID", unique = true, nullable = false)
public long getId() {
return this.id;
}

==============

http://www.hibernate.org/hib_docs/reference/en/html/mapping.html

ハマッた。。


前回の続き。

Hibernate annotaionには以下のライブラリが必要(漏れてたりしたら教えてください)
jarの名前とかバージョンとか違うかもしれません。

・Hibernate Core
 Annotaion
  ejb3-persistence.jar
  hibernate-commons-annotations.jar
:http://www.hibernate.org/6.html


・dom4j
:http://sourceforge.net/project/showfiles.php?group_id=16035

・commons-logging
:http://commons.apache.org/downloads/download_logging.cgi

・Log4J
:http://logging.apache.org/log4j/1.2/download.html

・commons-collections-3.2.1.jar
ないとでるエラー
java.lang.ExceptionInInitializerError
・・・
Caused by: java.lang.NoClassDefFoundError: org/apache/commons/collections/SequencedHashMap

・cglib.jar
ないとでるエラー
java.lang.ExceptionInInitializerError
・・・
Caused by: java.lang.NoClassDefFoundError: net/sf/cglib/proxy/CallbackFilter

・asm.jar
ないとでるエラー
java.lang.ExceptionInInitializerError
・・・
Caused by: java.lang.NoClassDefFoundError: org/objectweb/asm/Type

・jta.jar
ないとでるエラー
Exception in thread "main" java.lang.NoClassDefFoundError: javax/transaction/Synchronization
at org.hibernate.impl.SessionImpl.(SessionImpl.java:213)

これらはたいがいhibernate3.jarが入ってたアーカイブの中に同梱されてるはずです。

で、準備が終わったら、データのinsertを試してみる。
当然、お手本を探して真似する。
今回のお手本はここ。
http://d.hatena.ne.jp/inomas/20080331/1206958770

こんな感じ。

public class HibernateAnnotationTest {

private static final SessionFactory sessionFactory;
static {
try {
sessionFactory = new AnnotationConfiguration().configure().buildSessionFactory();
}catch (Throwable e) {
throw new ExceptionInInitializerError(e);
}
}

public static Session getSession() throws HibernateException {
return sessionFactory.openSession();
}

public void storeBook() {
Session session = getSession();

Book book1 = new Book();
Book book2 = new Book();

book1.setAuther("auther1");
book1.setIsbn("1234567890123");

book2.setAuther("auther2");
book2.setIsbn("1234567890123");

Transaction transaction = session.beginTransaction();

session.save(book1);
session.save(book2);

transaction.commit();
session.close();
}

}

てなもんで、これだけでしっかりデータが入りましたよ。

なんでもそうですけど、Hibernateはわかっていれば非常に開発効率を上げることができるスバラシーツールです。
ただマッピングのXMLファイルとかの作成がダルイ。
昔はmiddlegenとかを使ってそのダルさを回避してたけど、最近じゃHibernateご謹製のツールがEclipseのプラグインであるっぽい。前からあるのかもしんないけど。
しかも、最近じゃ、そのマッピングのXMLを使わずにannotationでイケるらしい。前からかもしんないけど。当然Hibernate Toolsはannotaionが入ったVO(DTO)も生成してくれる。

今回はとりあえず一番よくやりそうな、既に作成されているDBからリバースをやってみる。
マッピング嫌いだったから、annotaionのほうで。

まずは、インストールする。
下記のサイトからゲットして解凍して、pluginsとfeaturesをインストールされているEclipseにコピーして再起動で終わり。
http://www.hibernate.org/30.html

ついでに後で使うだろうから、他のHibernateライブラリもゲットしておいてもいいかも。NHibernateは.NET用のやつだから、ジャバーな僕達には要らない。

再起動したら、下記サイトで説明してくれているとおりに進める。
http://www.masatom.in/pukiwiki/index.php?Hibernate%2FHibernate%20Tools%A4%F2%BB%C8%A4%A6

このサイトはMySQLでやっているのでDerbyだと以下の変更点がある。
■hibernate.cfg.xmlの作成
・Database dialect: Derby
・Driver Class:org.apache.derby.jdbc.ClientDriver
・Connection URL:jdbc:derby://localhost:1527/DB名
 ※localhostとか1527とかDB名は環境に合わせて変更する
 ※Derbyのユーザー設定とかしてなかったら、ここも空でいい

■Console configurationの作成
これが何のためにあるのかよくわからなかったんですけど、調べた感じだとたぶん自動でいろいろやってくれるこのサポートツールの基本設定みたいなものっぽい。
お手本と違うところは、Derbyを使ってるので、特に外部Jarとかをここで設定する必要はないはず。
あと、

■hibernate.reveng.xmlの作成
特になし。

で、設定が完了したらコード生成。

お手本どおりHibernateパースペクティブに切り替える。
Window>Open perspectiveとかで適宜切り替える。

あとは基本お手本どおりで。

もし
org.hibernate.tool.hbm2x.ExporterException: File pattern not set on class
とかいうエラーに当たったら、ExporterタブのGeneric Exporterのチェックをはずしてみると幸せになれるかも。

これで、とりあえず生成は完了ということで。

次回?は生成したコードの利用ということで。


筆者の場合、なんかのプログラムを組むときにイキナリコードを書き始めることは稀で、まずインターネッツをして、組みたいコードの常套手段やら、フレームワークやら、流行やらを調査する。で、マネをしながら学習していく。

世の中すごい人が多いもので、筆者がマネをするのがやっとのものを、ご自分で開発効率性なり保守性なりの観点で優れたコードとかを書いて公開してくれて、かつ懇切丁寧に解説してくれているサイトがたくさんある。

けど悲しいかな、筆者の頭は相当悪い。ステップバイステップで説明してくれているのに理解できない。ところが同じようなことを説明しているのに絵があると、なぜか理解できる。絵といってもパワポ的なえじゃなくてマンガ的なやつ。

で、今日読んだのがコレ。
「やる夫がデザインパターンをやるようです。」

いや、わかりやすい。なぜかわからんけど。といったら書いた人に失礼だけど。

で、前置きが長くなったけど、本題に入ると、上記リンク先ページの下部に、シングルトンパターンのサンプルコードがある。
そこに、見慣れない、というか、Javaを初めてさわってから5年経つ筆者が初めて見るキーワードがあった。それがvolatileである。

リンク先では、
=============
// volatile指定子はuniqInst変数をYaruoGlobalインスタンスに対して初期化する際に
// マルチスレッドがuniqInst変数を正しく処理できるよう保障するものです
=============
という注釈が入っている。

これがどういうことなのかよくわからなかったので調べてみた。

結果からいうと、「volatileをつけた変数に関わる処理は書いたとおりに処理される。」ということだった。
んなのあたりめーじゃねーか!思われる方もいるかもしれない。

いやいやそうじゃないんですって!

プログラマが書いたコードは、コンパイラによってバイトコードに変換される。で、このコンパイラもガキの使いじゃなくって、筆者のようなショボショボのプログラマが書くショボショボのコードを幾分かマシな形にしてくれながら、バイトコードに変換する。

例えば
======
hoge="aaaaaa";//①
hoge="bbbbbb";//②
System.out.println(hoge);
======
とかいうコードがあったら①の処理はなかったことにする、みたいな。これを"最適化"っていうのかな。

で、やる夫の例でいくとこの部分が最適化の対象になる。
==========
// 同期コスト削減のため、まずnullかどうか聞く
if( uniqInst == null ){
// nullなら同期チェックしてnullのままならインスタンス生成
synchronized (YaruoGlobal.class ){
if( uniqInst == null ){
uniqInst = new YaruoGlobal();
}
}
}
==========
これは、synchronizedは重たい処理なので、ある程度振り分けを行っておこう、という意図で書かれている。つまり処理の結果としては、1回目の「uniqInst == null」はあってもなくても変わらない。
しかし、アクセス頻度の高い処理になる場合は、この1回目の処理があるかないかでは、システム全体の負荷が変わってくる可能性はある。

けれど、さすがに今のコンパイラはそういった意図まで汲めるほど賢くはない。つまり、おそらくコンパイラは1回目の「uniqInst == null」は最適化によって削除される可能性がある。※検証はまた今度しますので、気が向いたらしますのであらかじめご了承ください。

そして、あなたは負荷も意識したコードを書いたと思っているのに、なぜか解放されないメモリが溜まっていくという現象にぶち当たる。当然コードを見てもわからない。コンパイル前のコードはそういった状況にならないように組まれている(ように見える)のだから。

こんな事態を防ぐのがvolatileなわけです。これをつけた変数が絡む処理はコンパイラの最適化の影響を受けない。これであなたもスーパーハカー。

いや、知っている人からすれば、んなもん常識だよ。と言われるかも知れないですが、筆者は5年間かわし続けてきたわけですからね。
ちょっとぐらい得意げにさせてくださいよ。

なお、筆者がvolatileの用途を理解したのは、このサイトを見てです。
http://proger.blog10.fc2.com/blog-entry-20.html


このアーカイブについて

このページには、2008年5月以降に書かれたブログ記事のうちJavaカテゴリに属しているものが含まれています。

前のアーカイブはJava: 2008年4月です。

次のアーカイブはJava: 2008年7月です。

最近のコンテンツはインデックスページで見られます。過去に書かれたものはアーカイブのページで見られます。