-server
设置jvm使server模式,特色是启动速度比较慢,但运行时性能和内存管理效率很高,适用于生产环境。在具备64位能力的jdk环境下将默认启用该模式,而忽略-client参数。java
几台服务器的JVM占用内存老是持续增加,大大超过-Xmx设定的值,服务器物理内存几乎被耗尽。服务器
使用jmap查看JVM的内存使用,发现jvm的堆大小彻底在-Xmx参数设定的范围以内,那问题只能处在别的地方了。网络
JVM除了堆内存以外,就只有栈内存和DirectMemory了。栈空间每一个线程是固定的,线程数也没可能多到能够占用这么多内存的程序,因此怀疑的目标就在DirectMemory上了。jvm
DirectMemory是java nio引入的,直接以native的方式分配内存,不受jvm管理。这种方式是为了提升网络和文件IO的效率,避免多余的内存拷贝而出现的。 DirectMemory占用的大小没有直接的工具或者API能够查看,不过这个在Bits类中是有两个字段存储了最大大小和已分配大小的,使用反射能够 拿到这个数据:工具
Class<?> c = Class.forName("java.nio.Bits");
Field maxMemory = c.getDeclaredField("maxMemory");
maxMemory.setAccessible(true);
Field reservedMemory = c.getDeclaredField("reservedMemory");
reservedMemory.setAccessible(true);
Long maxMemoryValue = (Long)maxMemory.get(null);
Long reservedMemoryValue = (Long)reservedMemory.get(null);性能
结果证明了猜想,DirectMemory增加失控了。spa
原来,DirectMemory 的默认大小是64M,而JDK6以前和JDK6的某些版本的SUN JVM,存在一个BUG,在用-Xmx设定堆空间大小的时候,也设置了DirectMemory的大小。加入设置了-Xmx2048m,那么jvm最终可 分配的内存大小为4G多一些,是预期的两倍。线程
解决方式是设置jvm参数-XX:MaxDirectMemorySize=128m,指定DirectMemory的大小。orm