java堆外内存溢出_JVM 案例 - 堆外内存导致的溢出错误

案例

一个网站为了实现客户端实时从服务端接收数据,使用了 CometD 1.1.1 作为服务端推送框架,服务器是 Jetty7.1.4,CPU i5,内存 4G,操作系统 32位Windows。

服务端常常抛出内存溢出异常,管理员把堆开到最大(32位系统最多到1.6G),但问题依旧。

开着 jstat 观察,GC并不频繁,eden、survivor、老年代、永久代的内存都很正常,没有压力。

查看日志中有异常信息:

...

java.lang.OutOfMemoryError:null

...

at java.nio.DirectByteBuffer ...

原因

这是由 Direct Memory 不足引起的。

操作系统对每个进程能管理的内存是有限制的,32位windows的限制是2G,其中1.6G给了Java堆,但 Direct Memory 是不计入这 1.6G的,因此 Direct Memory 最大就是 0.4G。

垃圾回收时,虽然会对 Direct Memory 进行回收,但不像新生代、老年代那样,发现空间不足时就触发回收,只能等老年代满了之后 full gc 时,随便把 Direct Memory 清理一下,否则只能等抛出异常后进行catch,调用 System.gc()。

这个案例中使用了 CometD,有大量的 NIO 使用 Direct Memory,所以产生了这个问题。

总结

我们平时对堆比较关注,但一定要记得,除了堆之外,下面这些区域也会占用较多的内存,需要注意:

Direct Memory

可以通过 -XX:MaxDirectMemorySize调整大小,内存不足时抛出 OutOfMemoryError或者OutOfMemoryError:Direct buffer memory

线程堆栈

可通过 -Xss调整大小,内存不足时抛出 StackOverflowError(纵向无法分配,即无法分配新的栈帧)或者OutOfMemoryError:unable to create new native thread(横向无法分配,即无法建立新的线程)

Socket 缓存区

每个socket连接都有 receive 和 send 两个缓存区,分别占大约 37K 和 25K,连接多时占用的内存也很可观,如果无法分配,抛出异常 IOException: Too many open files 。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值