java虚拟机随手笔记(4)内存调优与案例分析

来源:互联网 发布:淘宝客服下班结束语 编辑:程序博客网 时间:2024/06/07 07:12

1.在高性能硬件上部署程序,目前主要有两种方式:通过64JDK来使用大内存。使用若干个32位虚拟机建立逻辑集群来利用硬件资源。

对于第一种方式,要控制好Full GC的频率,不然可能会导致服务长时间不响应,譬如十几个小时或者一天进行一次Full GC,可以在深夜进行。

对于第二种方式,具体做法是在一台物理机器上启动多个应用服务器进程,每个服务器进程分配不同端口,然后在前端搭建一个负载均衡器,以反向代理的方式来分配访问请求。 但是,很少没有缺点的方案,比如使用逻辑集群方式的话,可能会面临以下问题:资源竞争,尤其是磁盘竞争;很难高效的利用某些资源池,譬如连接池;各个节点仍然不可避免的受到32位的内存限制(2gb内存);可能会造成较大的内存浪费,因为每个逻辑节点都有一份缓存,可以考虑改为集中式缓存。


2.内存异常的抛出不仅仅是堆以及永久代,还可能是以下几个地方,

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

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

Socket缓存区:每个Socket连接都Receive和Send两个缓存区,分别占大约37KB和25KB内存,连接多的话这块内存占用也比较可观。 如果无法分配,则可能会抛出IOException:Toomany open files异常。)。

JNI代码:如果代码中使用JNI调用本地库,那本地库使用的内存也不在堆中。 

虚拟机和GC:虚拟机、 GC的代码执行也要消耗一定的内存


3.编译时间和类加载时间的优化:对于类加载时间,主要是字节码验证部分耗时很多,因此可以使用-Xverify:nono禁止掉字节码检验。

编译时间和垃圾收集时间也是两项很大的非用户耗时:

其中编译时间实际的是JIT编译,即java初步编译形成字节码(class文件),然后需要解释才能执行。为了解决程序解释执行的速度问题,JDK 1.2以后,虚拟机内置了两个运行时编译器,如果一段Java方法被调用次数达到一定程度,就会被判定为热代码交给JIT编译器即时编译为本地代码,提高运行速度(这就是HotSpot虚拟机名字的由来)。 甚至有可能在运行期动态编译比C/C++的编译期静态译编出来的代码更优秀,因为运行期可以收集很多编译器无法知道的信息,甚至可以采用一些很激进的优化手段,在优化条件不成立的时候再逆优化退回来。 所以Java程序只要代码没有问题(主要是泄漏问题,如内存泄漏、 连接泄漏),随着代码被编译得越来越彻底,运行速度应当是越运行越快的。 Java的运行期编译最大的缺点就是它进行编译需要消耗程序正常的运行时间,这也就是上面所说的“编译时间”。

对于垃圾收集时间,可以通过调整内存设置的方式来控制;这个的话,还是挺复杂的,不断的配置虚拟机的参数,包括新生代大小(-Xmn512m),老年代大小(-Xms,-Xmx),永久代大小(-XX:Permsize=128m),等等来配置内存空间,减少垃圾收集的次数和时间。还可以通过使用高效的垃圾收集器来减少垃圾收集时间。

0 0
原创粉丝点击