JVM的体系结构和垃圾回收机制

java虚拟机的体系结构图:



 

JVM内存区域介绍

  堆(Heap)

       Heap是大家最为熟悉的区域,它是JVM用来存储对象实例以及数组值的区域,可以认为Java中所有通过new创建的对象的内存都在此分配,Heap中的对象的内存需要等待GC进行回收,Heap在32位的操作系统上最大为2G,在64位的操作系统上则没有限制,其大小通过-Xms和-Xmx来控制,-Xms为JVM启动时申请的最小Heap内存,默认为物理内存的1/64但小于1G,-Xmx为JVM可申请的最大Heap内存,默认为物理内存的1/4,默认当空余堆内存小于40%时,JVM会增大Heap的大小到-Xmx指定的大小,可通过-XX:MinHeapFreeRatio=来指定这个比例,当空余堆内存大于70%时,JVM会将Heap的大小往-Xms指定的大小调整,可通过-XX:MaxHeapFreeRatio=来指定这个比例,但对于运行系统而言,为了避免频繁的Heap Size的大小,通常都会将-Xms和-Xmx的值设成一样,因此这两个用于调整比例的参数通常是没用的.堆内存大小(-Xmx)=Young区大小(-Xmn)+old区大小

 

  方法区

     方法区域存放了所加载的类的信息(名称、修饰符等)、类中的静态变量、类中定义为final类型的常量、类中的Field信息、类中的方法信息,当开发人员在程序中通过Class对象中的getName、isInterface等方法来获取信息时,这些数据都来源于方法区域,可见方法区域的重要性。同样,方法区域也是全局共享的,它在虚拟机启动时在一定的条件下它也会被GC,当方法区域需要使用的内存超过其允许的大小时,会抛出OutOfMemory的错误信息。

     在Sun JDK中这块区域对应的为PermanetGeneration,又称为持久代,默认为64M,可通过-XX:PermSize以及-XX:MaxPermSize来指定其大小。

 

栈(VM Stack)

     JVM栈是线程私有的,每个线程创建的同时都会创建JVM栈,JVM栈中存放的为当前线程中局部基本类型的变量(java中定义的八种基本类型:boolean、char、byte、short、int、long、float、double)、部分的返回结果以及Stack Frame,非基本类型的对象在JVM栈上仅存放一个指向堆上的地址,因此Java中基本类型的变量是值传递,而非基本类型的变量是引用传递,Sun  JDK的实现中JVM栈的空间是在物理内存上分配的,而不是从堆上分配。

      由于JVM栈是线程私有的,因此其在内存分配上非常高效,并且当线程运行完毕后,这些内存也就被自动回收。

      当JVM栈的空间不足时,会抛出StackOverflowError的错误,在Sun JDK中可以通过-Xss来指定栈的大小

 

  程序计数器

       PC寄存器是一块很小的内存区域,主要作用是记录当前线程所执行的字节码的行号。字节码解释器工作时就是通过改变当前线程的程序计数器选取下一条字节码指令来工作的。任何分支,循环,方法调用,判断,异常处理,线程等待以及恢复线程,递归等等都是通过这个计数器来完成的。

       由于Java多线程是通过交替线程轮流切换并分配处理器时间的方式来实现的,在任何一个确定的时间里,在处理器的一个内核只会执行一条线程中的指令。因此为了线程等待结束需要恢复到正确的位置执行,每条线程都会有一个独立的程序计数器来记录当前指令的行号。计数器之间相互独立互不影响,我们称这块内存为“线程私有”的内存。

       如果所调用的方法为native的,则PC寄存器中不存储任何信息

 

 

常见几种垃圾回收器

     串行收集器:

         串行收集器使用单线程处理所有垃圾回收工作,由于无需多线程交互,实现轻易,而且效率比较高。但是,其局限性也比较明显,即无法从多处理器硬件收益,所以此收集适合单处理器机器。当然,此收集器也可以用在小数据量(100M左右)情况下的多处理器机器上。串行垃圾收集器在一定的硬件和操作系统的配置时会缺省使用,也可以显式地用 -XX:+UseSerialGC 参数来指定。

 

     并行收集器:

         并行收集器使用多线程处理垃圾回收工作,因而速度快,效率高。而且理论上CPU数目越多,越能体现出并行收集器的优势。并行收集器在一定的硬件和操作系统配置下被缺省使用,同时,也可以使用 -XX:+UseParallelGC 参数来强制指定,线程数的多少可以用-XX:ParallelGCThreads=<N>参数来控制。

       需要说明的是,在J2SE5.0第6更新刚引入并行收集器时,在收集Young区是多线程的,但在Old区和第一种一样,仍然采用单线程并行垃圾收集器。后来在Java SE6.0中进行了增强–可以对 Old区 进行并行收集。如果年老代不使用并发收集的话,是使用单线程进行垃圾回收,因此会制约扩展能力。使用-XX:+UseParallelOldGC打开年老代使用并发收集。

 

     并发收集器:

            串行收集器和并行收集器进行垃圾回收工作时,需要暂停整个运行环境,因此,系统在垃圾回收时会有明显的暂停,而且暂停时间会由于堆越大而越长。而并发垃圾收集器并发地进行大部分垃圾收集工作(也就是在应用运行当中进行)来尽可能减少垃圾收集带来的应用停顿。它是为哪些拥有中到大量数据的、对响应时间要求高于吞吐量要求的应用,因为最小化时延的技术会让吞吐能力付出代价。并发垃圾收集器通过 -XX:+UseConcMarkSweepGC 参数来启用。它仅用于Old区的垃圾回收,此时Young区只能选择ParNew或Serial收集器中的一个,而不能选择Parallel Scavenge, 可以使用-XX:+UseParNewGC选项来强制指定使用并行的ParNew收集器。

         并 发垃圾收集器会在垃圾收集消耗时间过多的时候抛出 OutOfMemoryError 错误:如果多于 98% 的时间被花费在了垃圾收集上,并且仅有少于 2% 的堆被回收的话,就会抛出 OutOfMemoryError。这个功能是用来防止堆太小导致程序长时间无法正常工作而的

        下面是并发收集器回收垃圾过程的示意图,可以发现在初始标记和重新标记时需要暂停整个JVM,初始标记暂停的时间比重新标记的时间短。

 

     串行,并行垃圾回收器采用的都是暂停-复制的算法,而并发垃圾回收器采用标记—清除的算法

 

典型的线上jvm参数配置1

-server       让JVM以server模式运行

-Xms4g      堆的初始内存

-Xmx4g      堆的最大内存

-Xmn2g     年轻代大小

-XX:PermSize=96m     持久代初始内存

-XX:MaxPermSize=384m     持久代最大内存

-Xss1224k -XX:+UseConcMarkSweepGC    old区使用并发收集器

-XX:+UseCMSCompactAtFullCollection        打开对年老代的压缩.可能会影响性能,但是可以消除碎片

-XX:CMSMaxAbortablePrecleanTime=5000    保证CMS GC尽快完成对象的回收,避免concurrent mode failure的现象

-XX:+CMSClassUnloadingEnabled    为了避免Perm区满引起的full gc,启用类卸载策略 

-XX:+UseCMSInitiatingOccupancyOnly       old区在使用了初始化的比例后启动cms gc

-XX:CMSInitiatingOccupancyFraction=80   old区在使用了n%的后,触发cms gc

-XX:+HeapDumpOnOutOfMemoryError      堆内存溢出后dump出内存快照

-XX:HeapDumpPath=/home/admin/logs/java.hprof  堆内存溢出后dump出内存快照的存储文件

-verbose:gc -Xloggc:/home/admin/logs/gc.log       输出gc的信息和gc的日志输出文件

-XX:+PrintGCDetails           输出gc的详细信息

-XX:+PrintGCDateStamps   输出gc的时间戳

典型的线上jvm参数配置2

-server   让JVM以server模式运行

 -Xms3072m

-Xmx3072m

-Xmn1500m

-XX:PermSize=96m

-XX:MaxPermSize=256m

-XX:ParallelGCThreads=4   配置并行收集器的线程数,此值最好配置与处理器数目相等

 -XX:+UseCompressedOops   启用压缩指针.

-Xloggc:/home/admin/logs/gc.log

 -verbose:gc

-XX:+PrintGCDetails

-XX:+PrintGCDateStamps 

 

-server参数解释

   server模式默认采用并行回收GC,强制指定并行方式-XX:UseParallelGC

 -XX:+UseCompressedOops参数解释

     Java 的64位平台的性能比32位平台慢,原因是因为其指针由32位扩展到64位,虽然寻址空间从4GB 扩大到 256 TB,但导致性能的下降,并占用了更多的内存。所以对指针进行压缩。压缩后的指针最多支持32GB 内存,并且可以获得32位 JVM 的性能

 

参考文档

1.浅析JVM内存结构和6大区域:http://developer.51cto.com/art/201303/387175.htm

2.GC策略的调优:http://www.blogjava.net/BlueDavy/archive/2009/10/09/297562.html

3.jdk5,solaris5,调试CMS回收机制时的7点总结:http://blog.csdn.net/toella/article/details/7284167

4.Parallel Scavenge收集器:http://book.51cto.com/art/201107/278917.htm

5.了解CMS(Concurrent Mark-Sweep)垃圾回收器:http://www.iteye.com/topic/1119491

6.Java SE 6 Hotspot虚拟机垃圾回收调优:http://developer.51cto.com/art/201208/351690.htm

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值