当前位置: 首页 > 面试题库 >

当20%的堆仍然可用时,为什么会得到OutOfMemory?

支嘉祥
2023-03-14
问题内容

我将最大堆设置为8 GB。当我的程序开始使用约6.4 GB(如VisualVM中所述)时,垃圾回收器开始占用大部分CPU,并且在分配约100
MB时,该程序因OutOfMemory崩溃。我在Windows上使用Oracle Java 1.7.0_21。

我的问题是是否有GC选项可以帮助解决此问题。除-Xmx8g外,我什么也没有传递。

我的猜测是堆越来越碎片化,但是GC是否不应该压缩它?


问题答案:

我已经确定了点点滴滴的信息(这很困难,因为官方文档非常糟糕),我已经确定…

通常可能有两个原因,这两个原因都与自由空间的碎片化(即,存在于小块中的自由空间使得无法分配大对象)有关。首先,垃圾收集器可能不会进行压缩,也就是说不会对内存进行碎片整理。即使是执行压缩的收集器也可能无法很好地完成它。其次,垃圾收集器通常将内存区域划分为不同类型的对象保留的区域,并且它可能不会考虑从拥有内存的区域中获取可用内存以提供给需要内存的区域。

CMS垃圾收集器不进行压缩,而其他垃圾收集器(串行,并行,parallelold和G1)则进行压缩。Java 8中的默认收集器是ParallelOld。

所有垃圾收集器都将内存划分为多个区域,而且AFAIK都非常懒惰,因此很难尝试防止OOM错误。命令行选项-XX:+PrintGCDetails对于某些收集器在显示区域的大小以及它们具有多少可用空间方面非常有用。

可以尝试使用不同的垃圾收集器和调整选项。关于我的问题,G1收集器(启用了JVM标志-XX:+UseG1GC)解决了我遇到的问题。但是,这基本上是偶然的(在其他情况下,OOM更快)。一些收集器(串行收集器,cms和G1)具有广泛的调整选项,可以选择各个区域的大小,从而使您浪费时间徒劳地尝试解决问题。

最终,真正的解决方案令人不快。首先,是安装更多的RAM。其次,是使用较小的数组。第三,就是使用ByteBuffer.allocateDirect。直接字节缓冲区(及其int
/ float /
double包装器)是具有类似数组性能的类似于数组的对象,它们分配在OS的本机堆上。操作系统堆使用CPU的虚拟内存硬件,没有碎片问题,甚至可以有效地使用磁盘的交换空间(允许您分配比可用RAM更多的内存)。但是,一个很大的缺点是,JVM并不真正知道何时应该释放直接缓冲区,这使得该选项更适合长寿命的对象。最后,可能是最好的,当然也是最不愉快的选择是分配
和取消分配 使用JNI调用本机存储,并通过将其包装在Java中在Java中使用它ByteBuffer



 类似资料:
  • 下面是我的代码: 和控制台输出以下内容: 我以为使用toString可以去掉[],为什么它还在那里? 编辑:如果toString不是摆脱[]的正确方法,那么正确的方法是什么?

  • 隐藏程序是怎么处理碎片的?它只是将创建的视图设置为Gone吗?

  • 这是获取请求: 这是后端代码: 错误: CORS策略阻止了从源“http://localhost:3000”在“http://localhost:3001/”获取的访问:请求的资源上不存在“访问-控制-允许-起源”标头。如果不透明响应满足您的需求,请将请求的模式设置为“no-cors”以在禁用CORS的情况下获取资源。

  • 问题内容: 我想从文件中读取数据,但是在调用method 时得到了。即使我正在使用该方法,但它不起作用。 txt文件的第一行是: 问题答案: 怪罪法国语言环境:它使用逗号作为小数点分隔符,因此无法解析。 替换为可修复问题(演示1)。如果您想解析,请使用代替(demo 2 )。 您的代码中的第二个问题是使用用作分隔符。您应该使用单个反斜杠,否则包含的单词将破坏您的解析逻辑。

  • 我还尝试了,,JMeter获得了多达8000个示例,最大时间12000ms(超时30s),并给出了错误。在拒绝之前,它至少应该排队10,000个连接。

  • 问题内容: 我有一个MEAN项目。我在EC2机器上使用Jenkins,使用以下shell脚本构建它: 摩卡返回2(测试失败次数),但詹金斯仍然说: 完成:成功。 如果测试失败,我希望看到 完成:失败 您知道为什么它不能正常工作吗? 问题答案: 您可以: 使用像Karma这样的测试跑步者,或者 通过传递Mocha 标志,告诉Mocha以XUnit格式报告。XUnit与Jenkins理解的JUnit紧