JVM详解
JVM架构
垃圾回收
如何判断对象是否可以被回收?
引用计数法
引用计数方式最基本的形态就是 让每个被管理的对象与一个引用计数器关联 在一起,该计数器记录着该对象当前被引用的次数,每当创建一个新的引用指向该对象时其计数器就加1,每当指向该对象的引用失效时计数器就减1。当该计数器的值降到0就认为对象死亡。
可达性分析法
可达性分析法是通过以所有的“GC Roots”对象为出发点,如果无法通过GC Roots的引用追踪到的对象,那我们认为这些对象就不会再次被使用了,现在主流的程序语言都是通过可达性分析法来判断对象是否存活的。
垃圾回收算法
标记清除算法分为两个阶段:标记阶段 和 清除阶段。
标记阶段的任务是标记出所有需要被回收的对象,清除阶段就是回收被标记的对象所占用的空间。
标记清除算法实现非常简单,但是有一个比较严重的问题就是 容易产生内存碎片 ,碎片太多可能会导致后续过程中需要为大对象分配空间时无法找到足够的空间而提前触发新的一次垃圾收集动作。
复制算法将可用内存按容量划分为大小相等的两块,每次只使用其中的一块。当这一块的内存用完了,就将还存活着的对象复制到另外一块上面,然后再把已使用的内存空间一次清理掉,这样一来就不容易出现内存碎片的问题。
复制算法虽然实现简单,运行高效且不容易产生内存碎片,但是却对内存空间的使用做出了高昂的代价,因为 能够使用的内存缩减到原来的一半 。很显然,Copying算法的效率 跟存活对象的数目多少有很大的关系 ,如果存活对象很多,那么Copying算法的效率将会大大降低。
为了解决Copying算法的缺陷,充分利用内存空间,提出了标记整理算法。
该算法标记阶段和Mark-Sweep一样,但是在完成标记之后,它不是直接清理可回收对象,而是将存活对象都向一端移动,然后清理掉端边界以外的内存。
分代收集算法是目前大部分JVM的垃圾收集器采用的算法。它的核心思想是根据对象存活的生命周期将内存划分为若干个不同的区域。
一般情况下将堆区划分为老年代和新生代
- 老年代每次垃圾收集时只有少量对象需要被回收。
一般使用的是标记整理算法 - 新生代每次垃圾回收时都有大量对象需要被回收。
目前大部分垃圾收集器对于新生代都采取复制算法,因为新生代中每次垃圾回收都要回收大部分对象,也就是说需要复制的操作次数较少,但是实际中并不是按照1:1的比例来划分新生代的空间的,一般来说是将新生代划分为一块较大的Eden空间和两块较小的Survivor空间,每次使用Eden空间和其中的一块Survivor空间,当进行回收时,将Eden和Survivor中还存活的对象复制到另一块Survivor空间中,然后清理掉Eden和刚才使用过的Survivor空间。
JVM参数(常用)
标准参数(-)
参数 | 描述 |
---|---|
-verbose:class | 输出jvm载入类的相关信息,当jvm报告说找不到类或者类冲突时可此进行诊断。 |
-verbose:gc | 输出每次GC的相关情况。 |
-verbose:jni | 输出native方法调用的相关情况,一般用于诊断jni调用错误信息。 |
非标准参数(-X)
参数 | 描述 |
---|---|
-Xms512m | 设置 JVM初始内存 为512m。此值可以设置与-Xmx相同,以避免每次垃圾回收完成后JVM重新分配内存。 |
-Xmx512m | 设置 JVM最大可用内存 为512M。 |
-Xmn200m | 设置 年轻代大小 为200M。整个堆大小=年轻代大小 + 年老代大小 + 持久代大小。持久代一般固定大小为64m,所以增大年轻代后,将会减小年老 |
-Xss128k | 设置 每个线程的堆栈大小 。JDK5.0以后每个线程堆栈大小为1M,以前每个线程堆栈大小为256K。更具应用的线程所需内存大小进行调整。在相同 |
-Xloggc:file | 与-verbose:gc功能类似,只是将每次GC事件的相关情况记录到一个文件中,文件的位置最好在本地,以避免网络的潜在问题。 若与verbose命令同时出现在命令行中,则以-Xloggc为准。 |
-Xprof | 跟踪正运行的程序,并将跟踪数据在标准输出输出;适合于开发环境调试。 |
非Stable参数(-XX)
调试参数
参数 | 描述 |
---|---|
-XX:-PrintGC | 每次GC时打印相关信息 |
-XX:-PrintGCDetails | 每次GC时打印详细信息 |
-XX:-PrintConcurrentLocks | 遇到Ctrl-Break后打印并发锁的相关信息,与jstack -l功能相同 |
行为参数
参数 | 描述 |
---|---|
-XX:-UseConcMarkSweepGC | 对老生代采用并发标记交换算法进行GC |
-XX:-UseParallelGC | 启用并行GC |
-XX:-UseParallelOldGC | 对Full GC启用并行,当-XX:-UseParallelGC启用时该项自动启用 |
-XX:-UseSerialGC | 启用串行GC |
性能调优参数
参数 | 描述 |
---|---|
-XX:NewSize=size | 新生代区初始内存分配大小 |
-XX:MaxNewSize=size | 新生代区分配的内存的最大上限 |
-XX:NewRatio=2 | 新生代区与老生代区的内存比例 |
-XX:PermSize=size | 永久代区初始内存分配大小 |
-XX:MaxPermSize=size | 永久代区分配的内存的最大上限。在配置之前一定要慎重的考虑一下自身软件所需要的非堆区内存大小,因为此处内存是不会被java垃圾回收机制进行处理的地方。 |