目录 :1.java虚拟机内存模型
2.java内存分配参数
3.垃圾收集基础
4.常用调优案例和方法
5.实用JVM参数
6.实战JVM调优
1.java虚拟机内存模型
JVM将内存数据分为 程序计数器 虚拟机栈 本地方法栈 java堆 方法区
程序计数器(Program Counter Redister)是一块很小的内存空间。每个线程都有各自独立的一块程序计数器。
如果当前线程正在执行一个java方法,则程序计数器记录正在执行的java字节码地址。
如果当前线程正在执行一个Native方法,即本地调用,则程序计数器为空。
虚拟机栈也是线程的内存空间,java虚拟机栈的大小是动态的或者是固定的。java虚拟机规范中,定义了两种异常与栈空间有关。
StackOverflowError 和 OutOfMemoryError。如果虚拟机栈是固定的,栈的深度大于最大可用栈深度,则抛出StackOverflowError。
如果虚拟机栈是动态的,在扩展栈的过程中,没有足够的空间来支持栈的扩展,则抛出OutOfMemoryError。
在HotSpot虚拟机中 用-Xss 参数设置栈的大小。增加栈的空间大小后,支持函数调用的深度明显增加了。
在栈运行的时候,栈帧用来保存上下文数据。栈存放了 方法的局部变量表,操作数栈,动态链接方法和返回地址等信息,如果方法中的参数和局部变量较多,则占用空间大。
在使用大的对象的时候,使用完毕后,注意利用GC的回收机制将其回收。
本地方法栈是管理本地函数调用的。
java堆分为新生代和老年代 新生代又分为 eden(伊甸园)s0 s1(survivor 幸存者)
方法区 一块内存地址,被JVM中素有的线程共享。方法区主要保存的信息是类的元数据。
方法区保存类的信息,常量池,域信息,方法信息。在HotSpot虚拟机中,方法区也称为永久区,是一块独立于java堆的内存空间。虽然叫做永久区,但是在永久区中的
对象,同样也是可以被GC回收的。Hot Spot 对常量池的回收策略是 常量没有任何地方引用,就可以被回收了。String.intern()方法是指首先引用常量池中的对象。
如果Hot Spot 虚拟机确认某个类的信息不会被使用,也会将其回收,回收的基本条件至少有,所有该类的实例被回收,并且装载该类的ClassLoader被回收。
2.java内存分配参数
设置最大堆内存 -Xmx (新生代和老年代的大小之和的最大值)
设置最小堆内存 -Xms (JVM启动时,所占据的操作系统内存大小) 如果-Xms的数值较小,那么JVM会更频繁进行GC操作,用以释放失效的内存空间。对性能造成影响。
设置新生代 -Xmn 设置一个较大的新生代会减少老年代的大小,这个参数对系统的性能和GC的行为有很大的影响。新生代的大小一般设置为整个堆空间的1/4 到 1/3 左右。
在Hot Spot 虚拟机中 -XX:NewSize 用于设置新生代的初始大小, -XX:MaxNewSize用于设置新生代的最大值,-Xmn 等同于设计了相同的 -XX:NewSize -XX:MaxNewSize。
设置持久代(方法区) 持久代不属于堆的一部分。在HotSpot中 用 -XX:MaxPermSize 可以设置持久代的最大值,-XX:PermSize可以设置持久代的初始大小。
设置java虚拟机栈, 可以用 -Xss参数设置线程栈的大小。线程栈设置的内存越大,能开的线程数量越少。
对于栈空间不够的OutOfMemoryError,可以适量的减少堆的大小,释放出能多的系统内存,来开启更多的线程。
设置堆的比例分配 -XX:SurviviorRatio 用来设置新生代中 eden 和s0 的比例,s0 和s1 大小相同,职能一样,并在 Minor GC后,互换角色。
-XX:NewRatio=老年代/新生代
3.垃圾收集基础
基本问题:哪些对象需要回收? 何时回收这些对象 ? 如何回收这些对象?
垃圾回收算法与思想
引用计数法 由于无法处理循环引起的问题,引用计数法不适合jvm的垃圾回收
标记-清楚法(mark-sweep) 标记清楚法通过根节点标记所有可达对象,然后清楚所有不可达对象,完成垃圾回收。
复制算法 将from 和Eden 区域活跃的对象复制到to区域,然后清楚from区域和Eden区域所有的对象。
复制算法比较适用于新生代,因为在新生代,垃圾对象通常会多余存活对象,复制算法的效果会比较好。
标记-压缩算法 通过标记清楚算法回收之后,再把数据压缩的到内存的一端。
增量算法 一般垃圾回收的时候,会挂起应用程序,进行垃圾回收,直至回收完,但是如此会造成应用程序挂起时间太久,严重影响用户的体验或者系统性能。
增量算法不是一次将垃圾对象都回收完,而是间断性的执行应用程序代码,所以能减少系统的等待时间,但是因为线程切换额上下文的转换,使得总体成本上升,吞吐量下降。
分代思想
4.常用调优案例和方法
将对象预留在新生代 由于 FULL GC 的成本要远远高于Minor GC,因此,尽可能的将对象分配到新生代是一项明智的做法。
大部分情况下,将对象分配在新生代是合理的,但是对于大对象,却是值得商榷的,应该尽可能避免使用短命的大对象。
-XX:PretenureSizeThreshold=1000000 设置超过1M以上的对象直接分配到老年代。
设置对象进入进入老年代的年龄 -XX:MaxTenuringThreshold=15
一般来说稳定的堆大小对垃圾回收有利,获得一个稳定的堆大小的方法师使用 -Xms -Xmx 的大小一致。
稳定的堆大小虽然减少了GC的次数,但同时增大了GC的时间。为了加快单词的GC速度,JVM提供了两个参数用户压缩和扩展堆的空间。
-XX:MinHeapFreeRatio -XX:MaxHeapFreeRatio 堆空间空闲比例 默认值是40和70
5.实用JVM参数
JIT(Just in Time)编译器能够在运行时将字节码编译成本地代码,从而提高函数的执行效率。 -XX:ComplieThreshold (client 模式下是1500 ,server 模式下是10000)
堆快照对于java应用程序的性能优化和故障排查都是相当重要的。
使用-XX:+PrintGC 获取GC信息。使用-XX:+PrintGCDetails 输出更详细的信息。
类和对象跟踪 -XX:+TraceClassUnloading
控制GC
选择类校验器
……
6.实战JVM调优