《深入理解JAVA虚拟机》笔记6——调优案例分析与实战

时间:2022-12-28 12:58:32

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

控制Full GC频率的关键是看应用中绝大多数对象能否符合“朝生夕死”的原则,即大多数对象的生存时间不应该太长,尤其是不能产生成批量的、长生存时间的大对象,这样才对保障老年代空间的稳定。

如果计划使用64位JDK来管理大内存,还需要考虑下面可能面临的问题:
——内存回收导致长时间停顿
——现阶段,64位JDK的性能测试结果普遍低于32位JDK
——需要保证程序足够稳定,因为这种应用要是产生堆溢出几乎就无法产生堆转储快照(因为要产生十几GB乃至更大的dump文件),哪怕产生了快照也几乎无法进行分析。
——相同程序在64位JDK中消耗的内存一般比32位JDK大,这是由指针膨胀及数据类型对齐补白导致的。

如果计划使用集群方式来部署程序,可能会遇到下面一些问题:
——尽量避免节点竞争全局资源,最典型的就是磁盘竞争,各个节点如果同时访问某个磁盘文件的话(尤其是并发操作容易出现 问题),很容易导致IO异常。
——很难最高效率的利用某些资源池,譬如连接池,
——各个节点仍然不可避免的受到32位的内存限制,在32位windows平台中每个进程只能使用2GB内存,在某些unix系统中,可以提升到3GB乃至接近4GB内存,但32位中仍然受最高4GB内存的限制。
——大量使用本地缓存的应用,在逻辑集群中会造成较大的内存浪费,因为每个逻辑节点上都有一份缓存,这时可以考虑把本地缓存改为集中式缓存。

除了java堆和永久代之外,下面这些区域还会占用较多的内存,这里所有的内存总和会受到操作系统进程最大内存限制:
——direct memory:
——线程堆栈
——socket缓存区
——JNI代码
——虚拟机和GC

执行shell脚本是通过java的Runtime.getRuntime().exec()方法来调用的。java虚拟机执行这个命令的过程是:首先克隆一个和当前虚拟机拥有一样环境变量的进程,再用这个新的进程去执行外部命令,最后再退出这个进程。如果频繁执行这个操作,系统的消耗会很大,不仅是cpu,内存的负担也很重。

编译时间是指虚拟机的JIT编译器(just in time compiler)编译热点代码的耗时。为了解决程序解释执行的速度问题,JDK1.2以后,虚拟机内置了两个运行时编译器,如果一段java方法被调用的次数达到一定程度,就会被判定为热点代码,从而交给JIT编译器即时编译为本地代码,以提高运行速度(这就是HotSpot虚拟机名字的由来)。java运行期编译最大的缺点就是编译需要消耗程序正常的运行时间,也就是上面所说的“编译时间”。
虚拟机提供了一个参数-Xint禁止编译器运作,强制虚拟机对字节码采用纯解释方式执行。