JVM学习(1)

一、JVM介绍

       JVM就是Java虚拟机,是Java的程序运行的基础。它是一个抽象的机器,但像真正的机器一样有指令集,用于操作各种内存区域。JVM的主要作用就是管理内存区域,以及解释字节码文件。这个也是Java语言可以一次编译,到处运行的原因,只要有JVM在,就可以解释字节码文件,并执行。分别对应的JVM的GC机制和JIT机制。JVM总的来说是一种规范,类似于MySQL的存储引擎,是有多种实现的,我们常用的就是Oracle的hotspot,除此之外还有MSJVM。以及J9JVM等。

二、JVM内存模型

Java内存模型,又称为JVM的运行时数据区域,主要包含,堆,虚拟机栈,本地方法栈,元数据区,程序计数器,代码缓存区这些。这些的功能分别如下:

堆:堆一般来说是JVM中最大的一块区域,在JVM启动的时候分配,堆可以是物理上不连续的内存区域,只要是逻辑上连续即可。该区域主要用于存放对象实例。堆区域也是GC的主要区域,按这个来分,可以分为新生代,老生代。

虚拟机栈:虚拟机栈也是每个线程私有的区域,每个虚拟机栈是由栈帧组成的,每个栈帧包括局部变量表,操作栈,动态链接,以及方法返回地址。可以将栈帧理解为一个方法,变量表就相当于是方法的入参,或者方法的局部变量。操作栈存储的是方法的一条一条指令。动态链接,是指每个方法都在常量池中有一个引用,这里有动态链接是指向它的。方法的返回地址存的是方法被调用的地方,方法结束后,返回到方法被调用的地方。

本地方法栈:本地方法栈和虚拟机栈类似,区别是本地方法栈是给调用的本地方法使用的,而虚拟机栈是给Java程序使用的。本地方法也就是native修饰的方法,一般都是比较底层的方法,一般都是由C来实现的。Java也由办法通过JNI来访问虚拟机的运行时数据,但这种使用底层方法的方式会一定程度上脱离JVM的控制。

元数据区:该区域也是各个线程共享的区域,用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。在jdk8版本之前这块区域被称为永久代,永久代和元数据区的不同点在于,永久代会存储字符串常量。而元数据区不会,是将字符串存储到推内存中。

程序计数器:可以理解为Java程序在执行命令时的命令行指示器。之所以有程序技术器时因为Java实现多线程其实时多个线程轮流切换占用处理器处理的,因此为了让线程再切换回来后可以继续执行,需要有这个指示器来标注。也因此,每个线程使用的程序计数器都是不同的。是线程隔离的。

JIT:及时编译器,Java程序的运行包括编译和解释俩个步骤,并不是说所有的JVM都是这种模式,不过hotspot是按这种方式来执行Java程序的。Hotspot是由C1、C2,JIT编译器。C1对应的是client方式,该方式程序启动较快。C2对应的是server方式,该模式下峰值性能好。一般都是采取mix混合模式,即这两中编译器并存。JIT和C1、C2不同,全称为just in time编译器。这种编译器会检测热点代码,一般就是调用多次的方法,或者是循环。

三、GC

GC也就是垃圾回收机制,这个是区别于C语言的一个重要特征。C语言需要手动的申请内存与释放内存,这个在Java中就不需要,JVM帮我们做了这些。GC就是帮助释放内存的机制。

GC的对象是上述提到的堆空间以及元数据区。

其中堆空间分为新生代,和老年代。其中的新生代又可以继续细分为Eden区,from survivor 和to survivor 区。默认的这三个区的比例为8:1:1。新创建的对象都会在Eden区中,之后经历一次GC后会存入到其中一个survivor区中,之后GC的对象也都会存储到这个区域。当survivor区满了之后,会使用复制算法将该区的存活对象移入到另一个survivor区域中。当重复N次后,仍在survivor区中的对象,就会进入到老年代,大对象在第一次GC的时候就会直接进入到老年代。老年代会再进行GC,将确实没有引用的对象彻底清除,老年代用的GC算法默认是标记整理算法。

在新生代中发生的GC,一般都是minor GC,minor GC发生在新生代和元数据区,而full (major)GC一般发生在老年代。Full GC发生在minor GC后,新生代向来生代转移的对象大小,大于了老生代的剩余可用内存,即发生full GC。

Minor GC以及full GC都会造成STW,STW 即是当前的线程处理都会终止。但minor GC速度快,基本不会由问题,而full GC持续时间长,长时间full GC可能造成服务不可用或者重启。

       上述提到的复制算法,即是当一个survivor区占满的时候,将存活的对象都复制到另一个空的survivor区中,再将原先的survivor区彻底清除。这种方式的好处就是执行的速度很快,缺点是其中一个survivor是空的状态,有内存浪费。

而标记整理算法则是,先将有引用的对象打上标记,然后扫描整个内存区域,将没有标记的对象清理掉。并将还存活的对象整理到一起。除此之外,老年代还有标记清除算法,和标记整理算法类似,但没有整理的步骤,已造成内存碎片造成浪费。

目前常见的GC收集器如下:

新生代收集器:

Serial (-XX:+UseSerialGC)  --单线程

ParNew(-XX:+UseParNewGC) --多线程

ParallelScavenge(-XX:+UseParallelGC)--多线程,吞吐量可控

G1 收集器 --JDK7,商用GC收集器

老年代收集器:

SerialOld(-XX:+UseSerialOldGC)  --单线程

ParallelOld(-XX:+UseParallelOldGC)-- 多线程

CMS(-XX:+UseConcMarkSweepGC)-- 并发,但是标记清除算法

G1 收集器 --JDK7,商用GC收集器

GC收集器是如何判断对象是否可以回收的,是使用的根搜索算法。将对象直接的引用看作一张图,从GC ROOT节点开始搜索,找到这个节点的所有引用节点,那其他的节点就是无引用,可以GC的对象。

如图中的红色对象即是可以被GC掉的。 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值