java - System.gc() 收集仍然被局部变量引用的对象
问题描述
当我运行以下程序时
public static void main(String[] args) {
ArrayList<Object> lists = new ArrayList<>();
for (int i = 0; i <200000 ; i++) {
lists.add(new Object());
}
System.gc();
try {
Thread.sleep(Integer.MAX_VALUE);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
我转储堆
jmap -dump:live,format=b,file=heap.bin 27648
jhat -J-Xmx2G heap.bin
和ArrayList
200000 个对象丢失。
不知道为什么JVM知道对象不会被使用,为什么JVM判断这个GC根不是引用。
解决方案
局部变量本身不是 GC 根。Java® 语言规范定义:
可达对象是可以从任何活动线程的任何潜在持续计算中访问的任何对象。
很明显,它需要一个包含对对象的引用的变量,以便可以在活动线程的“潜在持续计算”中访问它,因此可以将此类变量的缺失用作易于检查的标志一个对象是不可到达的。
但这并不排除额外的努力来识别仍然被局部变量引用的无法访问的对象。规范甚至明确指出
可以设计优化程序的转换,将可到达的对象的数量减少到比那些天真地认为是可到达的要少。例如,Java 编译器或代码生成器可能会选择将不再使用的变量或参数设置为 null,以使此类对象的存储空间可能更快地被回收。
在同一部分。
是否确实如此,取决于当前执行模式等条件,即方法是解释运行还是已经编译。
从 Java 9 开始,您可以插入显式障碍,例如
public static void main(String[] args) {
ArrayList<Object> list = new ArrayList<>();
for (int i = 0; i <200000 ; i++) {
list.add(new Object());
}
System.gc();
try {
Thread.sleep(Integer.MAX_VALUE);
} catch (InterruptedException e) {
e.printStackTrace();
}
Reference.reachabilityFence(list);
}
这将强制列表保持活动状态。
以前的 Java 版本的替代方法是同步:
public static void main(String[] args) {
ArrayList<Object> list = new ArrayList<>();
for (int i = 0; i <200000 ; i++) {
list.add(new Object());
}
System.gc();
synchronized(list) {
try {
Thread.sleep(Integer.MAX_VALUE);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
但通常,您希望尽早收集未使用的对象。finalize()
只有当您与有关可达性的幼稚假设一起使用时,才会出现问题。
推荐阅读
- javascript - 下拉菜单中的多个负 z-index
- html - 我如何根据不同的 api 渲染 .pug 文件?
- html - 将内部 div 添加并附加到 div 并将函数附加到它
- django - 如何在我的视图中获取当前用户名?
- ruby-on-rails - 为什么 Rspec 找不到 select2 方法?
- pyspark - 将函数应用于具有列表作为 Pyspark 中的值的 RDD?
- html - 如何访问位于 public-html 内的其他域文件夹中的文件夹文件?
- ffmpeg - 将图像编码为 h264 和 rtp 输出:没有 sprop-parameter-sets 的 SDP 文件无法播放
- snowflake-cloud-data-platform - 在 Snowflake 中重新创建管道时保留负载历史记录
- java - 对 DynamoDB 表进行排序的任何合理方法?