jvm - 内存结构,GC

1.jvm的生命周期
(1) JVM在它的生存周期中有一个明确的任务,那就是运行Java程序。因此当Java程序启动的时候,就产生JVM的一个实例;当程序运行结束的时候,该实例也跟着消失了
(2) Java虚拟机总是开始于一个main()方法,这个方法必须是公有、返回void、直接受一个字符串数组。
     在程序执行时,你必须给Java虚拟机指明这个包含main()方法的类名。(可以在pom文件打包配置中指定)
     Main()方法是程序的起点,他被执行的线程初始化为程序的初始线程。程序中其他的线程都由他来启动。
     Java中的线程分为两种:守护线程 (daemon)和普通线程(non-daemon)。守护线程是Java虚拟机自己使用的线程,比如负责垃圾收集的线程就是一个守护线程。


2.java的内存模型 (JMM)
目的:解决Java多线程对共享数据的读写一致性问题
Java内存模型和jvm内存模型本没有关系,勉强对应,从变量,主内存,工作内存的定义看,主内存主要对应于java堆中的对象实例数据部分,工作内存则对应于虚拟机栈中的部分区域
主要对应于Java堆中的对象实例数据部分
(1) 主内存:
     Java中所有变量都储存在主存中,对于所有线程都是共享的
(2) 工作内存:
      每个线程都有自己的执行空间(即工作内存),线程执行的时候用到某变量,首先要将变量从主内存拷贝的自己的工作内存空间,然后对变量进行操作:读取,修改,赋值等,这些均在工作内存完         成,操作完成后再将变量写回主内存;


3.jvm的运行时数据区
(1) 线程私有区:每个线程私有的,线程私有数据区域生命周期与线程相同, 依赖用户线程的启动/结束而创建/销毁
     | - 程序计数器:
         i:当前线程所执行的行号指示器。(正在执行的虚拟机字节码指令的地址)
         ii:通过改变计数器的值来确定下一条指令,比如循环,分支,跳转,异常处理,线程恢复等都是依赖计数器来完成。
     | - Java虚拟机栈:用于执行Java方法

          i:每个方法执行都会创建一个栈帧,用于存放局部变量表,操作数栈,动态连接,和方法返回地址等信息

当前线程

当前栈帧

栈帧结构说明
局部变量表变量值存储空间,用于存放方法参数和方法内部定义的局部变量,在编译期确定容量
存放了编译期可知的各种基本类型(boolean、byte、char、short、int、float、long、double)、对象引用(reference 类型)和 returnAddress 类型(指向了一条字节码指令的地址)
操作数栈在做算术运算的时候就是通过操作数栈来进行的,又或者调用其它方法的时候是通过操作数栈来行参数传递的
动态连接每个栈帧都包含一个指向运行时常量池中该栈帧所属性方法的引用,持有这个引用是为了支持方法调用过程中的动态连接。
在Class文件的常量池中存有大量的符号引用,字节码中的方法调用指令就以常量池中指向方法的符号引用为参数。这些符号引用一部分会在类加载阶段或第一次使用的时候转化为直接引用,这种转化称为静态解析。
另外一部分将在每一次的运行期期间转化为直接引用,这部分称为动态连接
返回地址 方法的退出方式:正常完成和异常完成
正常完成:调用者PC计数器的值就可以作为返回值,栈帧中很可能会保存这个计数器值
异常完成:返回地址通过异常处理器来确定,栈帧中一般不会保存这部分信息

     | - 本地方法栈:
         i:一个Native Method就是一个java调用非java代码的接口
(2) 线程共享区
      | - Java堆:
           i:jvm管理的内存中最大的一块
           ii:用于存放对象实例,数组等
           iii:堆分代:新生代,老年代的默认比例是1:2
                 新生代(MinorGC次收集,频率高):包含Eden区,From Survivor区,To Survivor区  默认比例是8:1:1,所有新建的对象存放在Eden区,经过GC存活下来的对象存放在Survivor区
                 老年代(MajorGC 主收集,频率低):存放生命周期长的内存对象,新生代的对象经过N次GC存活下来,进入老年代
                 永久代: jdk1.7版本之后字符串常量池从永久代移除
                               1.8版本后永久代被移除,替代为元数据区Metaspace,元空间并不在虚拟机中,而是使用本地内存
                               GC不会在主程序运行期对永久区域进行清理
      | - 方法区:
          i:被JVM加载的类信息、常量、静态变量、即时编译器编译后的代码
          ii:运行时常量池 ----------  编译器和运行期(String 的 intern() )都可以将常量放入池中
== 直接内存
      i:并不是虚拟机运行时数据区的一部分,也不是Java虚拟机规范中定义的内存区域,但是这部分内存也被频繁地使用
      ii:受到本机总内存大小及处理器寻址空间的限制
== 直接内存(堆外内存)与堆内存比较
      i:直接内存申请空间耗费更高的性能,当频繁申请到一定量时尤为明显
      ii:直接内存IO读写的性能要优于普通的堆内存,在多次读写操作的情况下差异明显


4.GC算法
(1) 标记清除法/标记压缩法
     标记阶段:通过可达性分析算法,遍历所有的GC Roots对象,对从GC Roots对象可达的对象都打上一个标识,一般是在对象的header中,将其记录为可达对象
     清除阶段:清除的过程是对堆内存进行遍历,如果发现某个对象没有被标记为可达对象(通过读取对象header信息),则将其回收
     缺点:
            i:效率问题。标记和清除阶段的效率都不高(因为都需要遍历内存中的对象),而且GC时需要停止应用程序
            ii:空间问题。标记清除后村产生大量不连续的内存碎片,会导致在程序运行过程中需要分配较大对象时,因无足够的连续内存会提前触发垃圾回收动作
(2)复制收集算法
      原理:将可用内存按容量划分为大小相等的两块,每次使用其中的一块。当这一块的内存用完了,就将还存活的对象复制到另一块内存上,然后把这一块内存所有的对象一次性清理掉
      优点:简单高效,优化了标记/清除算法的效率低,内存碎片问题。(将存活对象复制到保留区域时也只按地址顺序存储的)
      缺点:
             i:将内存缩小为原来的一半,浪费了一半的内存空间,代价太高;
             ii:如果对象的存活率很高,极端一点的情况假设对象存活率为100%,那么我们需要将所有存活的对象复制一遍,耗费的时间代价也是不可忽视的。
(3)标记/整理算法
      原理:先标记出存活对象,然后让多有存活的对象都向一端移动,之后直接清理掉端边线以外的内存。
      缺点:标记/整理算法的缺点就是效率也不高,不仅要标记存活对象,还要整理所有存活对象的引用地址。
效率:复制算法 > 标记/整理算法 > 标记/清除算法
(4)分代收集算法
     新生代:复制收集算法(但是划分为Eden,From Survivor,To Survivor三个区域,比例为8:1:1)
                   GC开始时,对象存放于Eden区和From Survivor区,To Survivor区是空的,GC时,Eden区所有对象会被复制到To区,
                   From区的对象会根据GC存活的年龄决定是转移到年老区还是复制到To区,GC后,Eden区和From区都会被清空,
                   然后From区和To区会交换位置,保证To区是空的,然后进行下一次GC;
     老年代: 标记/整理算法或者标记/清除算法


当GC线程启动时(即进行垃圾收集),应用程序都要暂停(Stop The World)


5.Full GC触发条件:Full GC是针对整个堆
(1)年老代(Tenured)被写满
(2)持久代(Perm)被写满  ----  垃圾回收不会发生在永久代,如果永久代满了或者是超过了临界值,会触发完全垃圾回收(FullGC)
(3)System.gc()被显示调用
(4)堆中分配很大的对象  ----- 所谓大对象,是指需要大量连续内存空间的java对象,例如很长的数组,此种对象会直接进入老年代,而老年代虽然有很大的剩余空间,但是无法找到足够大的连续空间来分配给当前对象,
                                                 此种情况就会触发JVM进行Full GC
(5)CMS GC时出现promotion failed和concurrent mode failure
(6)统计得到的Minor GC晋升到旧生代的平均大小大于老年代的剩余空间


6.垃圾回收器
(1)Serial 收集器:单线程收集器,GC采用的是分代收集算法。
(2)ParNew 收集器:多线程收集器,和Serial原理相同
(3)Parallel Scavenge 收集器:新生代收集器,也是使用复制算法实现,同时也是并行的多线程收集器
(4)Serial Old 收集器:收集器的老年代版本,单线程,使用 标记/整理算法
(5)Parallel Old 收集器: Parallel Scavenge 收集器的老年代版本。多线程,使用 标记 —— 整理
(6)CMS 收集器:以获取最短回收停顿时间为目标的收集器。基于 标记 —— 清除 算法实现
(7)G1 收集器:面向服务端的垃圾回收器


7.JVM参数配置





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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值