はじめに
Javaにメモリを意識した実装は必要か?を読んで、書きたくなったポエム1です。Javaに特化した話ではないので、Javaタグは付けません。Java詳しくないし
Javaが解放した2、メモリに関する3つのもの
① 狭義のメモリリーク
Javaでは、メモリアドレスを言語仕様として扱うことができない。そのため、プログラム上は(通常の方法では)メモリを直接操作できず、狭義のメモリリーク(ヒープ領域の参照されていないメモリが解放されずに残ってしまう)が発生しない。
② メモリ解放のタイミング
GC利用時には、メモリ解放のタイミング(GC実行タイミング)は意識しない。プログラミング上で明示的にGC実行を促すこともできるが、特に最近のJavaでは、メモリ解放のタイミングをプログラミングで指定することは推奨されていない(気がする。出典なし)
③ メモリの上限
言語としての上限の指定は、どっかで外れた(気がする。出典なし)。実行時に上限を指定するのも昔に比べて推奨されなくなった(気がする。出典なし)。
Javaが解放しない、メモリに関する4つのもの
① 広義のメモリリーク
プログラミング上、使用できる(参照可能な)データのメモリは解放しない。プログラミング上使用可能であれば、実装者の意図に反しても(今後そのデータを使わないことが分かっていても)メモリを確保し続ける。
そのため、元記事の以下について、プログラミング上考慮する必要がある。
- GCで拾ってもらえるように変数のスコープを意識する。
- 使わなくなった参照が残らないようにする。(あくまで実装上で)
- (不必要に)static変数を使わない
弱い参照(weak reference)については割愛。
② メモリ解放(GC)の方式
Java11でGCの方式も追加されているようなので、方式の意識は必要(らしい)。この記事を書こうとして初めて知った
JDK-8204210: Implementation: JEP 333: ZGC: A Scalable Low-Latency Garbage Collector (Experimental)
JEP 333により巨大ヒープ向け低レイテンシGCが試験的に追加された
JDK-8204180: Implementation: JEP 318: Epsilon, A No-Op Garbage Collector
JEP 318により「何もしない(no-op)」GCが試験的に追加された
(参考) https://gist.github.com/ykubota/b37a62de579dc92d02c9483974160c67
③ 参照透過性
Javaは参照透過性を担保した言語ではないため、実行効率と保守性を考慮して、共通のオブジェクト(メモリ)を使用(参照)するか、複製するかの選択が必要なプログラミングを余儀なくされる。immutable論争というやつ。
④ スレッドセーフ
volatileとか。これも、メモリを意識して実行効率と保守性を考慮したプログラミングが求められる。大抵はフレームワークを使用することであまり意識せずにプログラムできる
メモリという視点で、未来のプログラムを考える
広義のメモリリークについては、現状でも静的解析等で回避できている部分はあるが、意識しないレベルではない。今後、AIなどの活用で、広義のメモリリークについても意識しないレベルでランタイム(トランスパイルやコンパイラ含む)が最適化するようになるのだろうか。
また、現在は、参照透過性が成り立つ言語では、メモリの複製による実行効率を意識した設計が必要(と思っている。出典なし)だが、今後、参照透過性が成り立つ言語でも、できるだけメモリを複製せずに(事前解析や遅延評価のような技術で)、ランタイムが最適化するようになるのだろうか。
そもそも、プログラミング言語が扱うメモリの概念自体にも大きな変化があるかもしれないし、プログラミングの仕方自体にも大きな変化があるかもしれない。
おわりに
Javaはプログラムの保守性(意識しないことを増やす)よりも実行効率重視だと思った。確かにそれ(意識しないことを増やす)はフレームワーク等で補完すべきだと思う。が関わることは、怖すぎてポエム以外で書ける気がしない。メモリの話とか、ランタイムや宗教