JVM总结

一.  Java中的内存划分

  • 程序计数器:保证线程切换后能恢复到原来的执行位置
  • 虚拟机栈:(栈内存)为虚拟机执行java方法服务:方法被调用时创建栈帧-->局部变量表->局部变量、对象引用
  • 本地方法栈:为虚拟机执使用到的Native方法服务
  • 堆内存:存放所有new出来的东西
  • 方法区:存储被虚拟机加载的类信息、常量、静态常量、静态方法等。
  • 运行时常量池(方法区的一部分)

注意, 因为 JDK7以后 已经移除了永久代, JDK8取而代之的是 metaspace

在 Java 中,堆被划分成两个不同的区域:新生代 ( Young )、老年代 ( Old )。新生代 ( Young ) 又被划分为三个区域:Eden、From Survivor、To Survivor。

二、判断对象死亡的两种常用算法

1、引用计数算法

概念:

  给对象中添加一个引用计数器,每当有一个地方引用它时,计数器值就加1;当引用失效时,计数器值就减1;任何时刻计数器为0的对象就是不可能再被使用的。

但是:

  主流的java虚拟机并没有选用引用计数算法来管理内存,其中最主要的原因是:它很难解决对象之间相互循环引用的问题

优点:

  算法的实现简单,判定效率也高,大部分情况下是一个不错的算法。很多地方应用到它

缺点:

引用和去引用伴随加法和减法,影响性能

致命的缺陷:对于循环引用的对象无法进行回收

2、根搜索算法:(jvm采用的算法)

概念:

  设立若干种根对象,当任何一个根对象(GC Root)到某一个对象均不可达时,则认为这个对象是可以被回收的。

注:这里提到,设立若干种根对象,当任何一个根对象到某一个对象均不可达时,则认为这个对象是可以被回收的。我们在后面介绍标记-清理算法/标记整理算法时,也会一直强调从根节点开始,对所有可达对象做一次标记,那什么叫做可达呢?

可达性分析:

  从根(GC Roots)的对象作为起始点,开始向下搜索,搜索所走过的路径称为“引用链”,当一个对象到GC Roots没有任何引用链相连(用图论的概念来讲,就是从GC Roots到这个对象不可达)时,则证明此对象是不可用的。

根(GC Roots):

说到GC roots(GC根),在JAVA语言中,可以当做GC roots的对象有以下几种:

1、(栈帧中的本地变量表)中引用的对象

2、方法区中的静态成员。

3、方法区中的常量引用的对象(全局变量)

4、本地方法栈中JNI(一般说的Native方法)引用的对象。

注:第一和第四种都是指的方法的本地变量表,第二种表达的意思比较清晰,第三种主要指的是声明为final的常量值。

在根搜索算法的基础上,现代虚拟机的实现当中,垃圾搜集的算法主要有三种,分别是标记-清除算法复制算法标记-整理算法。这三种算法都扩充了根搜索算法,不过它们理解起来还是非常好理解的。

 

三、垃圾回收算法:

1、标记-清除算法:

概念:

标记阶段:先通过根节点,标记所有从根节点开始的可达对象。因此,未被标记的对象就是未被引用的垃圾对象;

清除阶段:清除所有未被标记的对象。

缺点:

标记和清除的过程效率不高(标记和清除都需要从头遍历到尾)

标记清除后会产生大量不连续的碎片

2、复制算法:(新生代的GC)

概念:

  将原有的内存空间分为两块,每次只使用其中一块,在垃圾回收时,将正在使用的内存中的存活对象复制到未使用的内存块中,然后清除正在使用的内存块中的所有对象。

优点:

这样使得每次都是对整个半区进行回收,内存分配时也就不用考虑内存碎片等情况

只要移动堆顶指针,按顺序分配内存即可,实现简单,运行效率高

缺点:空间的浪费

  从以上描述不难看出,复制算法要想使用,最起码对象的存活率要非常低才行。

  现在的商业虚拟机都采用这种收集算法来回收新生代,新生代中的对象98%都是“朝生夕死”的,所以并不需要按照1:1的比例来划分内存空间,而是将内存分为一块比较大的Eden空间和两块较小的Survivor空间,每次使用Eden和其中一块Survivor。当回收时,将Eden和Survivor中还存活着的对象一次性地复制到另外一块Survivor空间上,最后清理掉Eden和刚才用过的Survivor空间。HotSpot虚拟机默认Eden和Survivor的大小比例是8:1,也就是说,每次新生代中可用内存空间为整个新生代容量的90%(80%+10%),只有10%的空间会被浪费。

当然,98%的对象可回收只是一般场景下的数据,我们没有办法保证每次回收都只有不多于10%的对象存活,当Survivor空间不够用时,需要依赖于老年代进行分配担保,所以大对象直接进入老年代。整个过程如下图所示:

37e28257-008e-40ad-a07f-1a45a38d4be2

 

 

3、标记-整理算法:(老年代的GC)

    复制算法在对象存活率高的时候要进行较多的复制操作,效率将会降低,所以在老年代中一般不能直接选用这种算法。

概念:

标记阶段:先通过根节点,标记所有从根节点开始的可达对象。因此,未被标记的对象就是未被引用的垃圾对象

整理阶段:将所有的存活对象压缩到内存的一端;之后,清理边界外所有的空间

优点:

  不会产生内存碎片。

缺点:

  在标记的基础之上还需要进行对象的移动,成本相对较高,效率也不高。

 

它们的区别如下:(>表示前者要优于后者,=表示两者效果一样)

(1)效率:复制算法 > 标记/整理算法 > 标记/清除算法(此处的效率只是简单的对比时间复杂度,实际情况不一定如此)。

(2)内存整齐度:复制算法=标记/整理算法>标记/清除算法。

(3)内存利用率:标记/整理算法=标记/清除算法>复制算法。

注1:标记-整理算法不仅可以弥补标记-清除算法当中,内存区域分散的缺点,也消除了复制算法当中,内存减半的高额代价。

注2:可以看到标记/清除算法是比较落后的算法了,但是后两种算法却是在此基础上建立的。

注3:时间与空间不可兼得。

 

4、分代收集算法:

  当前商业虚拟机的GC都是采用的“分代收集算法”,这并不是什么新的思想,只是根据对象的存活周期的不同将内存划分为几块儿。一般是把Java堆分为新生代和老年代:短命对象归为新生代,长命对象归为老年代

  • 存活率低:少量对象存活,适合复制算法:在新生代中,每次GC时都发现有大批对象死去,只有少量存活(新生代中98%的对象都是“朝生夕死”),那就选用复制算法,只需要付出少量存活对象的复制成本就可以完成GC。
  • 存活率高:大量对象存活,适合用标记-清理/标记-整理:在老年代中,因为对象存活率高、没有额外空间对他进行分配担保,就必须使用“标记-清理”/“标记-整理”算法进行GC。
  • 注:老年代的对象中,有一小部分是因为在新生代回收时,老年代做担保,进来的对象;绝大部分对象是因为很多次GC都没有被回收掉而进入老年代

你们的服务配置的虚拟机参数是怎么样的?

我们的服务的虚拟机参数:

-server       --启用能够执行优化的编译器,显著提高服务器的性能
-Xmx4000M     --堆最大值
-Xms4000M     --堆初始大小
-Xmn600M      --年轻代大小
-XX:PermSize=200M         --持久代初始大小
-XX:MaxPermSize=200M      --持久代最大值
-Xss256K                  --每个线程的栈大小
-XX:+DisableExplicitGC    --关闭System.gc()
-XX:SurvivorRatio=1       --年轻代中Eden区与两个Survivor区的比值
-XX:+UseConcMarkSweepGC   --使用CMS内存收集
-XX:+UseParNewGC          --设置年轻代为并行收集
-XX:+CMSParallelRemarkEnabled        --降低标记停顿
-XX:+UseCMSCompactAtFullCollection   --在FULL GC的时候,对年老代进行压缩,可能会影响性能,但是可以消除碎片
-XX:CMSFullGCsBeforeCompaction=0     --此值设置运行多少次GC以后对内存空间进行压缩、整理
-XX:+CMSClassUnloadingEnabled        --回收动态生成的代理类 SEE:http://stackoverflow.com/questions/3334911/what-does-jvm-flag-cmsclassunloadingenabled-actually-do
-XX:LargePageSizeInBytes=128M        --内存页的大小不可设置过大, 会影响Perm的大小
-XX:+UseFastAccessorMethods          --原始类型的快速优化
-XX:+UseCMSInitiatingOccupancyOnly   --使用手动定义初始化定义开始CMS收集,禁止hostspot自行触发CMS GC
-XX:CMSInitiatingOccupancyFraction=80  --使用cms作为垃圾回收,使用80%后开始CMS收集
-XX:SoftRefLRUPolicyMSPerMB=0          --每兆堆空闲空间中SoftReference的存活时间
-XX:+PrintGCDetails                    --输出GC日志详情信息
-XX:+PrintGCApplicationStoppedTime     --输出垃圾回收期间程序暂停的时间
-Xloggc:$WEB_APP_HOME/.tomcat/logs/gc.log  --把相关日志信息记录到文件以便分析.
-XX:+HeapDumpOnOutOfMemoryError            --发生内存溢出时生成heapdump文件
-XX:HeapDumpPath=$WEB_APP_HOME/.tomcat/logs/heapdump.hprof  --heapdump文件地址

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值