在分配一个应该很适合我为JVM提供的堆中的数据结构时,为什么会出现OutOfMemoryError? 这是我最近遇到的一个问题。

确实,当查看开发人员要完成的工作并通过-Xmx参数对提供给JVM的堆大小进行三重检查时,似乎确实存在着一些可疑之处。

30分钟后,我们了解了情况并解开了谜团。 但这确实起初并不明显,所以我认为如果我更详细地描述根本问题,可能会节省一天的时间。

与往常一样,了解问题的最佳方法是通过动手实例。 我构建了一个小的综合测试用例:

package eu.plumbr.demo;
class ArraySize {public static void main(String... args) {int[] array = new int[1024*1024*1024];}
}

代码很简单–它要做的就是分配一个包含十亿个元素的数组。 现在,考虑到java int原语需要4个字节,因此人们可能会认为使用6g堆运行代码可以很好地运行。 毕竟,这十亿个整数应该只消耗4g内存。 那么为什么执行代码时会看到以下内容?

My Precious:bin me$ java –Xms6g –Xmx6g eu.plumbr.demo.ArraySize
Exception in thread "main" java.lang.OutOfMemoryError: Java heap spaceat eu.plumbr.demo.ArraySize.main(ArraySize.java:6)

在投入更多的堆之前(事实上,使用–Xmx7g ,上面的示例运行得很好),让我们尝试了解为什么我们的期望是错误的。

首先– Java中的int原语确实需要4个字节。 因此,这并不意味着我们的JVM实现一夜之间变得疯狂。 而且我可以向您保证,数学运算也是正确的– 1024 * 1024 * 1024 int原语确实需要4,294,967,296字节或4 GB。

要了解发生了什么,让我们运行相同的情况,并通过指定–XX:+ PrintGCDetails来打开垃圾收集日志记录

My Precious:bin me$ java –Xms6g -Xmx6g -XX:+PrintGCDetails eu.plumbr.demo.ArraySize-- cut for brevity --Exception in thread "main" java.lang.OutOfMemoryError: Java heap spaceat eu.plumbr.demo.ArraySize.main(ArraySize.java:6)HeapPSYoungGen      total 1835008K, used 125829K [0x0000000780000000, 0x0000000800000000, 0x0000000800000000)eden space 1572864K, 8% used [0x0000000780000000,0x0000000787ae15a8,0x00000007e0000000)from space 262144K, 0% used [0x00000007e0000000,0x00000007e0000000,0x00000007f0000000)to   space 262144K, 0% used [0x00000007f0000000,0x00000007f0000000,0x0000000800000000)ParOldGen       total 4194304K, used 229K [0x0000000680000000, 0x0000000780000000, 0x0000000780000000)object space 4194304K, 0% used [0x0000000680000000,0x0000000680039608,0x0000000780000000)PSPermGen       total 21504K, used 2589K [0x000000067ae00000, 0x000000067c300000, 0x0000000680000000)object space 21504K, 12% used [0x000000067ae00000,0x000000067b087668,0x000000067c300000)

答案现在正盯着我们的眼睛:即使我们有很多可用的总堆,堆中的单个区域也没有足够大的空间来容纳4g对象。 我们的6g堆分为四个单独的区域,大小如下:

  • 伊甸园15.36亿
  • 生存空间( )每个256M
  • 老一代4,096M

现在,牢记对象分配必须适合单个区域,我们确实可以看到应用程序没有机会-我们的任何堆区域中都没有足够的空间来容纳此4g分配。

那么–我们现在唯一的希望是进一步增加堆数吗? 即使我们已经提供了将近50%的超额配置-将6g堆交给应该适合4g的数据结构? 没那么快–有替代解决方案可用。 您可以设置内存中不同区域的大小。 它并不像人们期望的那样简单易用,但对启动配置进行两次小的修改就可以解决问题。 使用两个额外的选项启动相同的代码时:

My Precious:bin me$ java -Xms6g -Xmx6g -XX:NewSize=5g -XX:SurvivorRatio=10 eu.plumbr.demo.ArraySize

然后程序执行其工作,并且不会引发OutOfMemoryError。 在启动中添加-XX:+ PrintGCDetails也会对此进行说明:

HeapPSYoungGen      total 4806144K, used 4369080K [0x00000006c0000000, 0x0000000800000000, 0x0000000800000000)eden space 4369408K, 99% used [0x00000006c0000000,0x00000007caaae228,0x00000007cab00000)from space 436736K, 0% used [0x00000007e5580000,0x00000007e5580000,0x0000000800000000)to   space 436736K, 0% used [0x00000007cab00000,0x00000007cab00000,0x00000007e5580000)ParOldGen       total 1048576K, used 0K [0x0000000680000000, 0x00000006c0000000, 0x00000006c0000000)object space 1048576K, 0% used [0x0000000680000000,0x0000000680000000,0x00000006c0000000)PSPermGen       total 21504K, used 2563K [0x000000067ae00000, 0x000000067c300000, 0x0000000680000000)object space 21504K, 11% used [0x000000067ae00000,0x000000067b080c90,0x000000067c300000)

我们看到,现在的区域大小确实是我们所要求的:

  • 如我们的-XX:NewSize = 5g参数所指定,年轻大小int总数(eden +两个幸存者空间)为5g
  • 如我们用-XX:SurvivorRatio = 10参数指定的,Eden比幸存者大10倍。

请注意,在我们的情况下,两个参数都是必需的。 仅指定-XX:NewSize = 5g仍会以某种方式将其在伊甸园和幸存者之间分割,使得任何区域都无法容纳所需的4g。

希望阅读此说明将为您节省以后的调试时间。 或帮助您避免过度配置资源。

翻译自: https://www.javacodegeeks.com/2014/05/outofmemoryerror-on-overprovisioned-heap.html

过度配置堆上的OutOfMemoryError相关推荐

  1. 教你打入clr内部: 配置windows上的windbg,linux上的lldb

    一:背景 1. 讲故事 前几天公众号里有位兄弟看了几篇文章之后,也准备用windbg试试看,结果这一配就花了好几天,(づ╥﹏╥)づ,我想也有很多跃跃欲试的朋友在配置的时候肯定会遇到这样和那样的问题,所 ...

  2. 教你配置windows上的windbg,linux上的lldb,打入clr内部这一篇就够了

    一:背景 1. 讲故事 前几天公众号里有位兄弟看了几篇文章之后,也准备用windbg试试看,结果这一配就花了好几天,(づ╥﹏╥)づ,我想也有很多跃跃欲试的朋友在配置的时候肯定会遇到这样和那样的问题,所 ...

  3. vs 编译器的堆空间不足_原创|面试官:Java对象一定分配在堆上吗?

    最近在看 Java 虚拟机方面的资料,以备工作中的不时之需.首先我先抛出一个我自己想的面试题,然后再引出后面要介绍的知识点如逃逸分析.标量替换.栈上分配等知识点 面试题 Java 对象一定分配在堆上吗 ...

  4. 结构体的两种声明方式:堆上和栈上以及在双链表的应用

    在看<算法精解:C语言描述>的双链表chtbl和redis的双链表adlist.c发现代码思路基本是一致的. 但是,对于链表的初始化却不一样 1.<算法精解:C语言描述>风格 ...

  5. 【性能优化】面试官:Java中的对象和数组都是在堆上分配的吗?

    写在前面 从开始学习Java的时候,我们就接触了这样一种观点:Java中的对象是在堆上创建的,对象的引用是放在栈里的,那这个观点就真的是正确的吗?如果是正确的,那么,面试官为啥会问:"Jav ...

  6. C++中栈和堆上建立对象的区别

    在C++中类的对象建立分为两种,一种是静态建立,如A a:另一种是动态建立,如A* p=new A(),A*p=(A*)malloc():静态建立一个类对象,是由编译器为对象在栈空间中分配内存,通过直 ...

  7. OC高级编程——深入block,如何捕获变量,如何存储在堆上

    OC高级编程--深入block,如何捕获变量,如何存储在堆上 首先先看几道block相关的题目 这是一篇比较长的  博文 ,前部分是block的测试题目,中间是block的语法.特性,block讲解b ...

  8. java 堆栈 对象_在Java中,哪些对象放在堆栈上,哪些放在堆上?

    对于 Java函数中的语句: Xxx xxx = new Xxx() { public Abc abc(final Writer out) { return new SomeFunction(out) ...

  9. Java 对象都是在堆上分配内存吗?

    为了防止歧义,可以换个说法:Java对象实例和数组元素都是在堆上分配内存的吗? 答:不一定.满足特定条件时,它们可以在(虚拟机)栈上分配内存. JVM内存结构很重要,多多复习 这和我们平时的理解可能有 ...

最新文章

  1. 多重集表示合json数据_计数DP(划分数,多重集组合数)
  2. 2022年你应该知道的机器学习算法
  3. 回望云计算发展 重新解读三种云服务
  4. 在CentOS下安装apche+tomcat+mysql+php
  5. Caused by: java.sql.SQLException: GC overhead limit exceeded处理百万数据出现的异常
  6. python蓝牙上位机开发_python做上位机 - osc_2frv0wjp的个人空间 - OSCHINA - 中文开源技术交流社区...
  7. SOL注入——HTTP头部注入(2)(七)
  8. 查询在具有最小内存容量的所有PC中具有最快处理器的PC制造商 (20 分)(两种思路+详解)
  9. Java案例:清洗网址垃圾字符
  10. linux sleeping进程多_Linux下找出吃内存的方法总结
  11. greys的简单使用
  12. 推荐中文分词:腾讯文智
  13. ERROR: Attempting to operate on hdfs namenode as root ERROR: but there is no HDFS_NAMENODE_USER defi
  14. GitHub星标数超4.2万的火爆之作!
  15. Android 四大组件 -- service
  16. 如何使用keepalive实现虚拟IP
  17. 惊!Go里面居然有这样精妙的小函数!
  18. clickHouse副本和同步机制
  19. 服务器错误信息36887,TLS 协议所定义的严重错误代码是 10。Windows SChannel 错误状态是 1203...
  20. 基于STM32的智能家居控制系统设计与实现(带红外遥控控制空调)

热门文章

  1. 【贪心】Sunscreen(poj 3614/luogu 2887)
  2. K8S Learning(4)——Namespace
  3. mybatis源码阅读(三):mybatis初始化(下)mapper解析
  4. 2019年这50个Kafka面试题,你知道答案么
  5. JavaFX UI控件教程(二十三)之Menu
  6. JDK8新特性之重复注解
  7. Spring Boot 发布 jar 包转为 war 包秘籍。
  8. 一步一步详解高斯日记
  9. java向数组中插入元素
  10. 2016蓝桥杯省赛---java---B---3(凑算式)