- GCのアルゴリズムの選択肢に委ねられているためですが、なぜ委ねられているのかが疑問かと思います。
原始的なマークアンドスイープ方式のGCであれば「GCを実行する」というのは単一のタスクとしてイメージしやすいのですが、コンカレントコレクタなどとなると、アプリケーションの実行停止を最小限に抑えるためにアルゴリズムが工夫されており、アプリケーションとGCが並行して走ったりするわけですね。
参考) https://www.jtp.co.jp/techport/2017-01-25-001/
このように並行してGCが走っている際に System.gc()が呼ばれたとしても「今、すでに走ってるから」となるわけで、今のGCが終わってから再度スケジューリングするのか、それともすでに走っているのだから無視するのか、といった選択肢が出てくるわけです。
- 現代的なGCであれば裏で並行して走っているようなイメージで良いのではないでしょうか。
GCのアルゴリズムはいろいろとあるのですが、近年のものはStop the worldを極力起こさないように工夫されていて複雑化しています。
https://blog.cybozu.io/entry/2018/05/29/080000
java コマンドで実行する際に -verbose:gc をつけるとガーベッジコレクションの動作ログが表示されるので見てみてはいかがでしょうか。
https://docs.oracle.com/javase/jp/11/tools/java.html
- あるオブジェクト X をあなたがもう使わないというつもりで破棄フラグを立てれたとしましょう。
しかし、他のオブジェクトからはオブジェクト X がまだ参照されています。何も知らない別スレッドからこのオブジェクト X が利用されたときに何が起こるべきなのでしょうか?
それとも、あるオブジェクト X を破棄するぞ、と決めた段階で、オブジェクト X への参照はすべてnullに置き換えられることが望ましいのでしょうか?
別スレッドでさっきまで参照していたオブジェクト X が急に null になって NullPointerExceptionを発生させる?
JavaのGCは参照が用いられなくなったことをGCが確認できてからオブジェクトを破棄する方式をとっています。これだと誤って破棄済みのオブジェクトをプログラマが触ることはありません。
その代わり、他のスレッド含めて参照がされなくなるタイミングまでオブジェクトの破棄ができませんから、明示的にオブジェクトの破棄を宣言することはできません。
明示的に破棄ができる方式だと、別スレッド主観でまだ使っている最中なのに突然にオブジェクトが破棄されてしまうという不整合が生じてしまいます。この方式だとマルチスレッドで気軽にオブジェクトを渡すようなプログラムを書くことはできませんよね。
方式によって一長一短あり、Javaでは破棄の自由を失う代わりに、破棄済みのオブジェクトを参照してしまう問題を考えなくてよくなっているというわけです。(メモリリークは別の問題として残りますが)
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。