图灵学院 java架构师学习-32位操作系统如何进行JVM性能调优详解
针对于64位JDK种种弊端,我们更多选择使用32位JDK集群来充分利用高性能机器的硬件资源。
如何实现?
在一个服务器上运行多个服务器程序,这些程序都在32位JDK上运行。然后将服务器作为反向代理服务器运行以实现负载平衡。
由于32位JDK最多支持2G内存,因此可以为每个虚拟节点分配1.6G堆内存。如果总共有10个虚拟节点在运行,则此物理服务器可以具有16G的堆内存。
有啥弊端?
多个虚拟节点竞争共享资源时容易出现问题
如多个虚拟节点共同竞争IO操作,很可能会引起IO异常。
很难高效地使用资源池
如果每个虚拟节点使用各自的资源池,那么无法实现各个资源池的负载均衡。如果使用集中式资源池,那么又存在竞争的问题。
每个虚拟节点最大内存为2G
别忘了直接内存也可能导致内存溢出!
问题描述
有一个小型网站,使用32位JDK,堆1.6G。在操作过程中,发现总是发生内存溢出。为了确定堆内存是否溢出,请在运行程序之前添加一个参数:-XX:HeapDumpOnOutOfMemeryError(添加此参数后,当堆内存溢出时,将输出异常日期)。但是,当再次发生内存溢出时,不会生成任何相关的异常日志。可以确定堆内存没有溢出。
问题分析
我们可以发现,在32位JDK中,将1.6G分配给堆,并将其一部分分配给JVM的其他内存,并且只有不到0.4G的内存是非JVM内存。我们知道如果使用NIO,JVM将在JVM内存之外分配内存空间。存储器的这一部分也称为“直接存储器”。因此,如果在程序中使用NIO,则在“直接内存”不足时,必须注意内存溢出异常!
直接内存的垃圾回收过程
直接内存虽然不是JVM内存空间,但它的垃圾回收也有JVM负责。直接内存的垃圾回收发生在FullGC时,只有当老年代内存满时,垃圾收集器才会顺便收集一下直接内存中的垃圾。
如果直接内存已满,但老年代没满,这时直接内存先是抛出异常,相应的catch块中调用System.gc()。由于System.gc()只是建议JVM回收,JVM可能不马上回收内存,那么这时直接内存就抛出内存溢出异常,使得程序终止。