Java JVM 5: 认识OOM

OutOfMemoryError对于Java猿们来说自然不陌生,但工作中真碰到这样的问题未免头大,那为什么会内存溢出?碰到这样的问题该怎么办?下面简单探讨。
众所周知,Java数据区包括栈、堆、方法区(直接内存),堆是用来放对象的,栈是用来放线程私有的,而方法区是存放类信息的,那么根据Java内存区域不同可以将OOM原因大致分为:

堆溢出

一般来说大部分Java的内存溢出应该属于这种情况,程序分配大量对象,且对象持有强引用的话便无法被GC回收从而造成OOM。
解决

  • 调大-Xmx参数分配更大的堆,在参数方面优化;
  • 通过MAT或Visual VM等各种工具分析大量占用堆空间的对象是否有必要,从在程序层面合理优化(比如采用享元模式实现对大量重复对象的复用)。
直接内存溢出

Java 的NIO可以直接操作直接内存,这块内存是直接向操作系统申请的堆外空间,申请速度慢但是访问速度快,适合作为可复用的、经常被访问的空间。直接内存没有被JVM完全托管,未必会触发GC,若使用不当易造成OOM。
这在32位机上可能比较明显(具体未验证),因为32位系统寻址空间为4G,其中2G用户空间,2G系统空间,实际可用内存只有2G。Java进程所有内存之和(堆、栈、直接内存及虚拟机自身内存)大于2G时便会OOM。
解决

  • 设置合理的-XX:MaxDirectMemorySize可以触发GC,若不设定默认最大可用直接内存为-Xmx的值。
永久区溢出

存放类元数据的区域,显而易见,若创建太多的类(注意是类而非对象)可能导致OOM。
解决:

  • 增加MaxPermSize的值。
  • 减少系统不必要类的数量。
过多线程导致溢出

每个线程的开启都要占用系统内存,线程数量太多也可能导致OOM,但是实际应用中估计没人会会开太多线程,往往会用线程池做到线程复用。但作为一个原因这里暂且列出。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值