Javaに関連するTips。今後はJavaで実装する機会も少なくなるとは思うけど、おりにふれて追記していく予定。

インストール

インストール

# 最新バージョンのインストール
brew cask install java # 2019年4月現在だとjdk12がinstallされる

# 過去バージョンのインストール
brew tap homebrew/cask-versions
# brew cask install java8 #配布停止ずみ
brew cask install adoptopenjdk8
brew cask install java11

JAVA_HOME確認

/usr/libexec/java_home -v 1.8
> /Library/Java/JavaVirtualMachines/adoptopenjdk-8.jdk/Contents/Home
/usr/libexec/java_home -v 11
-> /Library/Java/JavaVirtualMachines/openjdk-11.0.2.jdk/Contents/Home
/usr/libexec/java_home -v 12
-> /Library/Java/JavaVirtualMachines/openjdk-12.0.1.jdk/Contents/Home

JAVA_HOME切り替え

aliasを設定しておき、java12, java8のような感じで切り替える

alias java8='export JAVA_HOME=`/usr/libexec/java_home -v 1.8`'
alias java11='export JAVA_HOME=`/usr/libexec/java_home -v 11`'
alias java12='export JAVA_HOME=`/usr/libexec/java_home -v 12`'

メモリ調査関係

ローカルで動いているjavaの監視

  • GCの実行
  • ヒープダンプ取得
    jvisualvm -J-Xmx1024m

jConsole

  • メモリ使用状況をリアルタイム監視
  • 外からGCをかけられる

java プロセスIDを調べる

jps -l

GCの手実行

jcmd ${プロセスID} GC.run

thread dumpの取得

jstack ${プロセスID} > ${ファイル名}   # hoge.tdump

heap dumpの取得

df -h /${対象フォルダ}
jmap -dump:format=b,file=${ファイル名} ${プロセスID}   # hoge.hprof

Eclipse Memory Analizer

  • Eclipse Plugin
  • ローカルPCで実行中のJVMやGCダンプを取り込んで分析
    • 実行中のJVMを分析する場合、取り込んだタイミングで、いったんdumpファイルが作成される
    • 1Gクラスのdumpファイルを解析するには、それを読み込む必要がありそれだけで数分かかった・・・
  • Leek suspects -> Dominator Treeを見ていくと、メモリリークしているオブジェクトが分かる
  • 「Shallow Heap」はそのオブジェクト自体のサイズ。「Retained Heap」はそのオブジェクト+子オブジェクトの合計サイズ
    • 子オブジェクトの「Retained Heap」の合計 + 自オブジェクトの「Shallow Heap」 = 自オブジェクトの「Retained Heap」
    • 同じオブジェクトを複数オブジェクトから参照している場合、ダブルカウントされるかどうか、よく分からず?

テスト

jMockitoで実行時の挙動を上書き(static methodもOK)

new MockUp<Hoge>() {      // 対象のクラスを指定
  @Mock
  public void fuga(Invocation inv, final Request request, final Response response) {  // 属性、メソッド名、引数は合わせる
    // do something
    inv.proceed();
  }
};

リフレクション

フィールドの値を取得して書き換える

Class<Hoge> clazz = Hoge.class;

// このクラスから参照不可能なものも含めた全フィールド一覧取得
Field[] declaredFields = clazz.getDeclaredFields();
// このクラスから参照不可能なものも含めたフィールド取得
Field declaredField = clazz.getDeclaredField('fuga');

// このクラスから参照可能なフィールド一覧取得
Field[] fields = clazz.getFields();
// このクラスから参照可能なフィールド取得
Field field = clazz.getField('fuga');

// 値の設定
Hoge hoge = new Hoge();
field.set(hoge, "dummy_string");

input stream

String <=> Input Stream

// String -> Input Stream
String input = "0000000001\n0000000002\n0000000003";
InputStream is = new ByteArrayInputStream(input.getBytes("utf-8"));

// Input Stream -> String
BufferedReader reader = new BufferedReader(new InputStreamReader(is, "utf-8"));
reader.lines().forEach(line -> {});

その他

時間計測

long start = System.currentTimeMillis();
//do something
long stop = System.currentTimeMillis();
System.out.println("実行時間: " + (stop - start));