java - 即使 Old Gen 已满,JVM 也不存在 OOM 问题
问题描述
我看到了这个关于 JVM 内存的有趣问题。这真的很令人困惑。考虑这种情况:不断将一个新对象放入 HashMap 中,而这个对象只有一个 String 字段。应该是OOM,因为我没有覆盖hashcode()和equals(),结果结果不是,JVM一直在做GC。所有对象都被HashMap强引用,为什么没有OOM?
public class FinalTest {
private final String key;
FinalTest(String key){
this.key = key;
}
public void getKey(){
System.out.println( key);
}
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException{
Map<FinalTest,String> map = new HashMap<>();
for(;;){
map.put(new FinalTest("a"),"v");
System.out.println(map.toString());
}
}
}
jconsole 截图:
然后我删除了那个打印命令,结果不一样了......
老一代用法:
曲线在最后一刻下降,因为伊甸空间被清除了。然后看起来进程被阻止(老一代已满)。此外,即使老一代已满,它仍然不会产生 OOM 异常。
为什么这两种情况不同?为什么没有OOM异常?
解决方案
对于循环的每次迭代,map.toString()
分配的内存比实际大得多map.put(new FinalTest("a"),"v");
,因此 toString 隐藏了 map.put 分配的影响。
因此,您的堆内存图表显示了很多尖峰,因为有大量可垃圾回收的字符串。
更改日志行以打印大小,您将看到 map.put() 调用正在逐渐消耗所有可用内存,并且当收集整数->字符串堆时,每次 GC 的更改越来越少:
System.out.println(map.size());
一旦您进行了上述更改 - 或注释掉了System.out.println
运行速度将会提高,因为需要更少的 GC,并且您将获得java.lang.OutOfMemoryError: Java heap space
预期的结果。
推荐阅读
- ruby-on-rails - Rails 5.2 部分计数器:“未定义的局部变量或方法”错误
- php - "Use of undefined constant" error while trying to display image in codeigniter
- excel - 基于多个条件的查找值
- apache-spark - Spark SQL - how to add two column value
- ios - UISlider 的 minView 超出了它的边界和拇指的中心
- jquery - Change css of div when ajax return success
- laravel - 在表单 datalist 中显示列表用户名并在表中发送 user_id
- sql - 如何从 ddl 生成表 - SQL Data Modeler 到 SQL Developer
- reactjs - React Js + Laravel 路由到 web 或 api?
- sockets - C:服务器/客户端套接字程序 - 客户端错误连接