【深入理解JAVA虚拟机】第二部分.内存自动管理机制.5.调优实战

高性能硬件上的程序部署策略

在高性能硬件上部署程序,目前主要有两种方式:
  通过64JDK来使用大内存。    --  缺点:GC停顿时间长
  使用若干个32位虚拟机建立逻辑集群来利用硬件资源。   -- 思想: 分治,汇总。 缺点:分布式/多实例的缺点,如数据共享,数据一致性,一致性hash等。

堆外内存导致的溢出错误 

垃圾收集进行时,虚拟机虽然会对Direct Memory进行回收,但是Direct Memory却不能像新生代、 老年代那样,发现空间不足了就通知收集器进行垃圾回收,它只能等待老年代满了后Full GC,然后顺便地帮它清理掉内存的废弃对象。 否则它只能一直等到抛出内存溢出异常时,先catch掉,再在catch块里面大喊一声:“System.gc()!

从实践经验的角度出发,除了Java堆和永久代之外,我们注意到下面这些区域还会占用较多的内存,这里所有的内存总和受到操作系统进程最大内存的限制。
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的代码执行也要消耗一定的内存。

外部命令导致系统缓慢

执行这个shell脚本是通过JavaRuntime.getRuntime().exec()方法来调用的。

这种调用方式可以达到目的,但是它在Java虚拟机中是非常消耗资源的操作,即使外部命令本身能很快执行完毕,频繁调用时创建进程的开销也非常可观。

Java虚拟机执行这个命令的过程是:首先克隆一个和当前虚拟机拥有一样环境变量的进程,再用这个新的进程去执行外部命令,最后再退出这个进程。

如果频繁执行这个操作,系统的消耗会很大,不仅是CPU,内存负担也很重。 

服务器JVM进程崩溃

等待的线程和Socket连接越来越多,最终在超过虚拟机的承受能力后使得虚拟机进程崩溃。

不恰当数据结构导致内存占用过大

解决:减小大小,减少持有时间

Windows虚拟内存导致的长时间停顿

原因:客户端最小化时,会把工作内存移到磁盘页面文件之中,导致GC变慢。

发现:加入参数-XX+PrintGCApplicationStoppedTime-XX+PrintGCDateStampsXloggcgclog.log

扫描二维码关注公众号,回复: 5141696 查看本文章

解决:-Dsun.awt.keepWorkingSetOnMinimize=true

IDE启动慢

原因:初始堆太小,启动过程中触发N此扩容,每次扩容前判断扩容的前提是fullGC后内存不足,所以已经触发了N次fullGC。

解决:初始内存扩大。

猜你喜欢

转载自www.cnblogs.com/aoyihuashao/p/10348143.html