Javaに関する様々な情報をご紹介します。

Javaに関する様々な情報をご紹介します。
評価

0

フィールド定数をメソッドに置き換えることのデメリットを知りたい

パソコンやスマホのスペックは年々向上しており、メモリを意識せずにコーディングしてもなんとかなる状況(決して良くはない)が増えてきています。
反面、組み込み系やWEBアプリ等では、スペックの制限やアクセスの集中等を考慮し、メモリを意識してコーディングする必要があると考えています。

メモリの節約を図る上では、定数をことごとくメソッドに置き換えることも有効な手段のひとつではないかと考えています。
ですが、そういったコーディングをあまり目にしたことがないので、何かデメリットがあるのではないか?とも感じていますが、考えてもわからないので皆様のお知恵をお借りできればと思います。


その上で、僕自身のJVMの理解、解釈についてもお話をさせてください。

まず、JVMはざっくりとスタック領域とヒープ領域(とパーマネント領域)に分かれています。
メソッドが呼び出されるとメソッドの先頭アドレスがスタック領域に格納され、メソッド終了時に結果(返り値)が取り出され自動的に開放されます。
if文やfor文などの基本構文のスコープの中で宣伝された変数も同様であり、変数単位で考えるならばローカル変数がスタック領域に格納されています。

対して、ヒープ領域にはメソッドが終了しても利用されるデータが格納され、ガベージコレクションにより動的に解放されます。
newして生成したインスタンスの本体もそれらのデータのひとつであり、フィールド定数および変数もこのインスタンスの本体に内包されています。
また、ガベージコレクションにより領域が解放される明確なタイミングをコーディングで指示する事はできません。

つまりは、フィールド定数および変数の使用を最小限にすることで、アプリケーションが使用するメモリの節約になり、Full GCを抑制するという副産物もあるのではないと考えています。
定数に注目しているのは、定数は全てメソッドに置き換え可能だと考えているためです。

3

回答

2743

閲覧

3件の回答

評価

0

すみません、ひとつ補足をさせてください。
参照型のフィールド定数を他の値または参照型変数と比較する必要がある場合は、メソッドへの置き換えについて考慮すべきと考えています。
主にcase文の引数に代入されるような定数です。

評価

30

考えたことなかったけど、今考えたことを書いてみる。

・定数はコンパイル時あるいはJITでインライン展開され、宣言したクラスが参照されなくなる(newやstaticメソッドの戻り値は実行時の可能性が高いが)。同様にメソッドも単純ならコンパイル時にあるいはJITでインライン展開され、参照されなくなる。展開前提だと両者の効率は同じになる(かも知れない)。
・展開されない場合、メソッド呼び出しにはオーバーヘッドがある。
・展開されても宣言そのものは残る。パーマネント領域内のフィールド分のメモリとメソッド分のメモリを比較すると、メソッドの方が大きい(確実にそうかどうかは知らない)。
・単純に、コンパイラや各種最適化(コンパイル時、実行時)が頭良すぎな現状では、正直最適な状態になるコードを予測しづらい。
・何より、メモリ効率は確かに重要だが、大抵は微々たるものであり、思想を曲げて追及すべきものではない。
本当にメモリ効率を追求したいなら高級言語なんて使わない方がいいって話になるし。

ところで
>メソッドの先頭アドレスがスタック領域に格納され
これは聞いたことがなかった…認識漏れしてるんだろうか。

評価

0

ご回答ありがとうございます。

まず、事前コンパイルの事ばかりでJITコンパイラの事が抜け落ちておりました。
また、コンパイラに対する理解と勉強が足りていなかった事を実感しています。

「JITでインライン展開」というのがかなり重要なキーワードと思ったので、まずはJITの理解を深めるため下記のPDFを読みました。
https://www.oracle.com/webfolder/technetwork/jp/javamagazine/Java-MA16-JIT.pdf
ざっくり要約すると、呼ばれる機会の多いメソッドは事前コンパイルされ、そうでないメソッドはJITコンパイラにより実行時に動的コンパイルされると理解しました。

次に僕の不勉強で「インライン展開」という言葉を初めて目にしたので、こちらについても調べました。
つまりは、極力オブジェクト指向を使わないコードに置き換えることで、メソッドやフィールド変数・定数等を呼び出す処理時間を削減しようという事ですね。

自分の不勉強と理解不足を自己補填した上で、ご解説いただいた事について理解、納得が出来ました。
ありがとうございます。

定数のメソッド化はおそらく単純な構造なので、インライン展開され、効率には差がない。
くわえて、多くのケースでは定数よりもメソッドの方がパーマネント領域を大きく確保する。
という2点で普通に定数で宣言しておく方が良いだろうと理解しました。

そして、回答者さんのおっしゃるとおりで、Javaのコンパイラや各種最適化が優秀すぎて、それらの詳細な仕組みについては僕の考えや理解が及ばないです。
また、僕のメモリや低級言語への理解が、Java開発陣の人達に敵うわけがない。
となると、メモリ効率にこだわるよりも、ソースコードの拡張性や可読性等といった設計部分の方にこだわった方が生産的だと今は思っています。

>メソッドの先頭アドレスがスタック領域に格納され
については、単に僕の認識違いかもしれません。
どこでこの文言を目にしたかを正確には覚えてないのですが、WEB上の記事であり、かつOracleやSun Micro Systemsの資料からではないのは確かなので、間違った情報を僕が鵜呑みにしているかもしれないです。

回答する

ログインしていません。

ログインしなくても回答はできますが、ログインすると、質問・回答の管理、更新があった場合のメールでの通知を受けることができます。 アカウントをお持ちでない方は会員登録を行ってください。

ユーザ名匿名