jvm总结

1.jvm 运行时数据区模型、jvm逻辑图、java栈帧逻辑图
 
    
          a)线程独享内存
            指令计数器:存放当前执行的字节码指令地址。
            java方法栈:以栈帧为单位存放当前运行方法的详细信息,栈帧为方法运行时的数据结构,栈帧主要分为局部变量表、操作数栈、动态链接和出口。
                 局部变量表:方法入参和在方法内部定义的本地变量。
                 操作数栈:执行指令时所需的操作数值
                 动态链接:即方法运行所需要的在方法运行时才转换为直接引用的常量池中常量的符号引用
            本地方法栈:
        b)线程共享内存
            方法区:存放类加载器加载的类信息、常量、静态变量、即时编译器 编译后的代码数据(JIT:如通过动态代理生成的代理类信息)。
            java堆:大部分java对象存放在java堆中。


2.java堆内存模型
                
jdk1.8之前的堆内存模型:
    
jdk1.8之后的堆内存模型:
    
    一般年轻代的中Eden区和survivor区的比例为8:1:1,这样年轻代的可用率为90%,用两个survivor区会使得按代回收更方便,这样能够使得对象能够在年轻代中存活多次。

3.对象空间分配

    指针碰撞:系统保存则一个指向可用空间起始地址的指针,在分配对象时就从这个地址开始分配,分配完后修改该指针的地址,只能在没有内存碎片的连续内存空间中使用指针碰撞来分配空间,在多个线程同时分配对象时需要额外的开销来保证线程安全。

    空闲列表(Free Table):如果在不是很规整的内存中分配空间,则需要一个空闲列表来记录那些内存是可用的。
    本地分配线程缓存(TLAB:Thread Local Allocation Buffer :因为线程可能会频繁创建对象,而如果一直在主内存中分配为新创建的对象分配空间时,则每次都要执行cas操作来保证线程安全。如果在线程创建后为该线程预先分配一块内存缓冲区,每次创建对象都会直接在自己的内存缓存区中分配内存,这样就减少了分配内存使用需要执行额外的cas操作。

4.垃圾回收
     判断对象是否存活
        指针引用:每个对象多有一个引用计数器,如果这个计数器中值为0,即没有对象应用了,则说明该对象不存活,会存在当对象之间存在环形引用时就不能对这些对象进行回收的问题。
        
        gc可达:如果通过gc root对象可以访问到的对象就是gc可达的,不能访问到的对象就为gc不可达,gc不可达的对象就需要回收。
            gc root节点:静态常量池中的常量和全局变量,一个对象gc可达表示通过gc root对象的引用链能够方法到该对象。
            对象引用的类型分为强引用、软引用、弱引用、虚引用
                强引用:一般创建的对象间的引用都为强引用,这只有gc不可达(引用关系不存在)时才可能会被回收。
                软引用: 通过java.lang.ref.SoftReference对创建的对象进行包装之后的对象,就为软引用,当内存不足时,即使引用关系还存在,也会被回收。
                弱引用:通过 java.lang.ref.WeakReference对 创建的对象进行包装之后的对象,就为弱引用,在下一次gc时一定会被回收。
                虚引用:用来标记对象需要被回收,虚引用跟没有引用时一样的效果,只是虚引用的对象暂时还在内存里。

    分配担保
    当执行youngGc时,为了保证能够将年轻代下所有可能存活的对象,则需要老年代进行担保,以保证如果to survivor区不能存放所有的存活对象时,能够将对象保存到老年代,如果老年代连续可用空间大于年轻代所有对象总大小,则担保成功,如果分配担保失败,则会检查jvm是否允许担保失败即检查HandlePromotionFailure标志,如果为true,则检查老年代连续可用内存是否大于历史平均晋升老年代对象大小,如果不大于,则会触发full gc。

      gc回收算法
            标记清除:扫描指定堆内的所有对象给所有gc可达的对象打上标记,然后清除所有未标记的对象。这样会造成好多内存碎片。(cms使用该回收算法)
            标记整理:扫描指定堆内的所有对象给所有gc可达的对象打上标记,然后将打了标记的对象推到堆的前端,然后将不可达的对象清除。这样在gc回收时会耗时更多。(一般年老代会使用该算法)
            标记复制:扫描指定堆内的所有对象给所有gc可达的对象打上标记,然后将打了标记的对象移到另一块堆内存内,然后将原来的堆整体清除掉。这样就会有一部分内存浪费(年轻代使用这个回收算法)
                
     HotSpot 中的垃圾回收器
            年轻代回收器:
                单线程回收器:serial(标记复制)
                多线程回收器:parNew(标记复制)
                基于吞吐量的多线程回收器:parallel scavenge(标记复制)
            年老代回收器:
                单线程回收器:serial old(标记整理)
                基于单次最短停顿时间的回收器: cms( Concurrent Mark-Sweep )(标记清理)
                基于吞吐量的多线程回收器:parallel Old(标记整理)
            年轻代老年代通用的回收器:G1(分区,最先回收最大可回收空间的分区)
    cms 步骤:初始化标记、并发标记、重新标记、并发清理

    oopMap:用来保存方法栈的数据引用对象,这样在垃圾回收时就可以很快的找到所有的对象引用从而判断该对象是否需要回收。
    但如果每一条会使引用发生变更的命令上都添加一个oopMap对象的话会加大方法栈消耗的内存,而为了减少内存消耗,则需要在那些对象引用变化不是很频繁的命令上添加oopMap对象,这些使对象引用不会很频繁发生变化的命令都有一个特点,就是能够使程序长时间执行,如方法调用、循环跳转和异常跳转,而在垃圾回收时需要使所有用户线程挂起,而为了是垃圾回收时能够快速的标记出所有gc可达的对象,则需要线程那些存放了oopMap对象的命令上挂起,所有这些节点被称为安全点。

    安全点:使程序长时间执行的命令-方法调用,循环跳转、异常跳转。
    安全区域:如果用户线程一直在执行的话,当gc线程发出了要用户线程停顿的命令的话,用户就好在很短的时间内到达安全点,但是如果用户线程处于sleep或blocked,这样的话就可能要很长一段时间到达下一个安全点,而安全区域就是用来标记线程进入了一块不会对对象引用做出修改的代码块,这样当gc线程要执行挂起用户线程时对于这些处于安全点的线程就可以不用理会直接执行垃圾回收,而当处于安全区域的线程在退出安全区域前必须要检查一下垃圾回收线程是否还在执行,如果还在执行则将自己挂起,等待垃圾回收线程来唤醒。




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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值