1968年~1974年にかけて、アメリカ・カリフォルニア州で少なくとも5人が殺害された未解決事件「ゾディアック事件」で、犯人が残した暗号文である「340暗号文」が51年越しに解読されたと報じられています。
⇧ 51年越しって...
オランチャク氏らによる暗号解読を受けて、FBIはサンフランシスコ・クロニクルを通じて「FBIはゾディアック事件の暗号が民間人によって解読されたことを認識しています。当該事件は、地元の法執行機関との協力により現在も捜査が進められています」との声明を発表しました。
⇧ 捜査が継続されてるってのも驚きだけど、暗号が解読されても手掛かりになるような情報にならなかったところが辛いところですね。
そんなこんなで、今回もJavaについてです。
レッツトライ~。
Javaの型とメモリ領域
Javaの全てのオブジェクトは、JVM(HotSpot VMに限定?になるのかな)側のOOP(Ordinary Object Pointer)って仕組みで管理されてるっていうことが分かったわけなんですが、
Javaって「静的型付け」な言語ということで、「型」についてきっちりしているということなんですが、大きく分けて、
- プリミティブ型 ※1
- 参照型 ※2
※1:boolean型、byte型、char型、long型、short型、int型、float型、double型
※2:Boolean型、Byte型、Character型、Long型、Short型、Integer型、Float型、Double型といったラッパークラス、Decimal型、String型、Object型などなど
に分かれると思うんだけど、JVM(Java Virtual Machine)ってのは、「.java」ファイルがJDK(Java Developmet Kit)なんかに同梱されてる「javac」のようなコンパイラーで「.class」ファイルが生成されてから、初めて処理を進めることができると思われるわけなんだけど(JVMの概要図とか見ると「Class Loader」が起点になってるので)、
⇧ 「.class」ファイルの内容は、上図で言うと「JVM Memory」のいずれかに配置されていくのだと思うのですが、「プリミティブ型」と「参照型」って配置される場所ってどうなるんだっけ?
ってことで、
This article explains the internal architecture of the Java Virtual Machine (JVM). The following diagram show the key internal components of a typical JVM that conforms to The Java Virtual Machine Specification Java SE 7 Edition.
⇧ 上記サイト様がJVMの内部について解説してくれています。
「Java SE 7」時点の内容ということで、「Java SE 8」で「PermGen(Permanent Generation for VM metadata)」とか無くなって、JVMのMemory構成が変わってるあたりとかの影響とかが分からないのですが、参考になるかと。
で、説明を読んでいくと、
- プリミティブ型
- Stack
- Frame
Local Variables Array
- Frame
- Stack
- 参照型
- Stack
- Frame
Current Class Constant Pool Reference- Class Data
Run-Time Constant Pool
- Class Data
- Frame
- Heap
- Stack
って感じで、「プリミティブ型」「参照型」で配置されるJVMのMemory領域が異なりますと。「参照型」については、インスタンス化してオブジェクトになったら「ヒープ」領域に配置されるんだと思われます。
Pool of Stringsって?
で、ようやっと本題。
String型ってのは、Javaの場合「参照型」に分類されると思うんだけど、ちょっと特殊な管理をされてるっぽいんですよ。
どういうことかと言うと、
public final class String extends Object implements Serializable, Comparable<String>, CharSequence
String
クラスは文字列を表します。Javaプログラム内の"abc"
などのリテラル文字列はすべて、このクラスのインスタンスとして実行されます。
https://docs.oracle.com/javase/jp/8/docs/api/java/lang/String.html
⇧ まず、第一に、「リテラル」でインスタンス化できるという。
普通だと「new演算子」でコンストラクタでインスタンス化するってのが一般的だと思われますが、String型は、
String str = "abc";
String str = new String("abc");
char data[] = {'a', 'b', 'c'}; String str = new String(data);
⇧ ってな感じで、「new演算子」を使わなくても、使っても、どちらでもインスタンス化できますと。
で、本題の「Pool of Strings」ですが、
public String intern()
文字列オブジェクトの正準表現を返します。
文字列のプールは、初期状態では空で、クラスString
によってプライベートに保持されます。
internメソッドが呼び出されたときに、equals(Object)
メソッドによってこのString
オブジェクトに等しいと判定される文字列がプールにすでにあった場合は、プール内の該当する文字列が返されます。そうでない場合は、このString
オブジェクトがプールに追加され、このString
オブジェクトへの参照が返されます。
https://docs.oracle.com/javase/jp/8/docs/api/java/lang/String.html#intern--
⇧おそらく、java.lang.String#intern()メソッドの「文字列のプール」のことを指しているのではなかろうかと、java.lang.Stringのjavadoc(ドキュメント)を見ても「プール」について言及してるのが、java.lang.String#intern()メソッドの部分だけなので。
ただ、例の如く「文字列のプール」については何なのか説明はないという、流石、Oracleさん、安定の不親切さ。
なので、ネット上は大混乱です。
「String Constant Pool」って言葉も出てきたりして、もう情報が錯綜しまくり。だから、あれほどドキュメントは曖昧にするなと言ったのに、って偉い人が言ってくれれば良いんですけどね...
そんなわけで、推測するしかないんだけど、
⇧ おそらく「Current Class Constant Pool Reference」が参照してる「Run-Time Constant Pool」の中の「string constants」って部分が「Pool of Strings」ってことなんじゃないかと。
ただ、「new演算子」でインスタンス化したオブジェクトは「ヒープ」領域に配置されると思われるので、
⇧ String型のオブジェクトってやつは、
の2か所に分散されてるってことみたいね。それぞれのオブジェクトへの参照値ってのは「Current Class Constant Pool Reference」に作成されるんでしょうね。
このあたりの検証をされてる方がおりまして、
⇧ 上記サイト様が詳しいです。
それにしても、Javaって相変わらず情報が錯綜してますね、公式のドキュメントで記載の無い情報が多過ぎるからだとは思いますが、25年間以上こんな感じってのが絶望的ですね...
今回はこのへんで。