Java中jvm虚拟机详解

 1.什么是JVM

         JVM是java虚拟机英文单词的缩写,jvm是一种用于计算设备的规范,它是一个虚构出来的计算机,是通过在实际的计算机上方针模拟各种计算机功能来实现的。Java虚拟机包括一套字节码指令集,一组寄存器,一个栈,一个垃圾回收堆和一个存储方法域。jvm屏蔽了与具体操作系统平台相关的信息,是Java程序只需生成在java虚拟机上运行的目标代码(字节码),就可以在多种平台上不加修改的运行。JVM在执行字节码时,实际上最终还是把字节码解释成具体平台上的机器指令执行。

         Java语言的一个重要的的特点就是跨平台性,而使用java虚拟机就是实现这个特点的关键。引入java语言虚拟机之后,java语言就不需要重新编译。Java虚拟机屏蔽了具体平台相关信息,将字节码对象解释成相关平台的机器指令执行。

  2.jre/jdk/jvm关系

       Jre是java运行环境,也就是java平台。所有java程序都要在jre下才能运行。

Jdk是程序开发者用来编译,调试java程序用的开发工具包。Jdk的工具也是java程序,也需要jre才能运行。通常jre是jdk安装的一部分。

Jvm是jre的一部分。

JDK :  JRE+开发工具(一些执行命令)

JRE: JVM+核心类库(java所需要的核心类)

JVM:保证语言的跨平台

    3.JVM原理

.java(源代码)→.class(字节码)→类加载器→字节码校验器→解释器/jit代码生成器→硬件

Jvm虚拟机三大执行引擎:1.解释器,2.jit代码生成器(第一次执行将字节码编译成本地机器代码,放在系统缓存中),3.一种自适应的优化器(将频繁执行的代码段编译成本地机器代码)

  4.JVM的体系结构(内存管理机制)

1.java栈内存,每个线程都拥有自己的栈,存储的信息包括局部变量,执行环境,操作数栈。局部变量是类的方法中所用到的局部变量。执行环境用来保存解析器对于java字节码进行解释过程中需要的信息,包括上次调用的方法,局部变量指针和数栈的栈顶栈底指针。操作数栈用来存储运算所需要的操作数和结果。Java栈内存在方法被调用时创建,在某个线程某个时间点上,只有一个栈内存是活跃的。栈内存中的方法被执行完之后,或者调用别的栈内存中的方法时,则当前栈内存变成了另外一个栈内存。栈内存的大小有固定和动态两种,动态类型的栈内存按照线程的需要分配。

 两个栈内存的关系和转换

2.java堆是用来存放对象信息的,栈内存代表着一种运行时状态。换句话说,栈是运行时单位,解决程序的执行问题,而堆是存储单位,解决数据存储问题。堆和栈的存储空间都是不连续的。

3.程序计数寄存器,是一个较小的内存空间,它的作用可以看做当前线程执行的字节码的行号指示器。字节码解释器工作时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令,分支,循环,跳转,异常处理,线程恢复等基础功能都需要依赖这个计数器来完成。Java中的多线程是通过线程轮流切换并分配处理器执行时间的方式来实现的,一个内核只会执行一条线程中的指令。每条线程都有一个独立的程序计数器,方便线程切换后能回复到正确的执行位置。

4.方法区,用来存放所加载的类的信息,类的名称,修饰符,类中的静态变量,类中的final常量,类中的方法信息。当程序中使用类加载器时读取类时,所有的数据都来源于这个区域。方法区域是全局共享的,当方法区域使用的内存超过其允许的的大小时,会报出outofmemory内存溢出的错误,就会被GC垃圾回收。

5.运行时常量池,存放类中固定的常量信息,方法和field的引用信息等,它属于方法区域

6.本地方法堆栈,jvm采用本地方法堆栈来支撑本地机器码执行,该区域存储每个native方法的调用状态。

 

  5. JVM的垃圾回收机制

         Java很难控制jvm的内存回收,只能根据原理去提高程序的性能。

随着程序的运行,内存中存在的实例对象,变量等信息占据的内存会越来越多,必须要进行及时的垃圾回收,否则会使程序性能下降,甚至会因为可用内存不足出现异常。

上上图中的jvm的五个内存区域有三个不需要进行垃圾回收:程序计数寄存器,JVM栈,本地方法栈。因为他们的生命周期都是和线程绑定的,线程销毁内存自动释放。只有方法区和堆需要GC垃圾回收。

垃圾判定算法:引用计数算法和根搜索算法

经典垃圾判定机制为引用计数算法,每个对象添加一个引用计数器,一段时间内不引用,就会被回收,但当两个对象相互引用时,不会被垃圾回收,因此JVM不采用这种方法,采用根搜索算法。

根搜索算法:从一个GCRoots的对象开始,向下搜索,一个对象不能到达GC Roots对象时,就会被垃圾回收。

对于某个对象的使用(引用),在1.2之后进行扩充,分为强引用,弱引用,软引用和虚引用。

1.强引用:刚被new的对象所加的引用,永远不会被回收

2.软引用:声明为软引用的类,如果内存紧张就会被回收,否则不会。软引用的使用是利用了缓存机制,方便使用,提高程序的性能

3.弱引用:对象一定需要进行垃圾回收,不关内存紧张不紧张,当进行GC时,立马会被清理回收

4.虚引用:唯一作用是辅助finalize()函数(对根搜索算法进行补充,当一个对象向上连接不到GC Roots对象时,系统会调用一次finalize()方法,如果在这个期间重新与GC Roots对象连接时,这个对象会重生)的使用

JVM的内存被分成新生代,旧生代和持久代,三代特点不同,GC算法就不同。

新生代:新生对象存放在新生代.目标就是尽可能快速收集掉那些生命周期短的对象.新生代分成三个区,一个Eden区和两个Survivor区.对象在Eden区生成,当Eden区满时复制到Survivor区,Survivor区满时,扔存活的对象进入旧生代。

旧生代:存放生命周期较长的对象。

持久代:存放静态文件。被称为方法区。Jdk8持久代被换成元空间,不占用虚拟机内存,而使用本地内存。

垃圾回收算法:标记-清除算法、复制算法、标记整理算法、分代收集算法

1.标记清楚算法:相当于两个人一前一后,前面的人叫标记,后面的人叫清除,标记需要垃圾回收的对象,后面清除对对象进行清除,会产生许多内存碎片

2.复制算法:将内存划分成许多小块,存活的对象复制到下一个小块,然后对之前的小块进行彻底清除,适用于清除存活率较小的情况。

3.标记整理算法:将内存划分成两块,将存活的对象储存在一遍,另一块彻底清除,划分大小按照存活的对象多少而定,适用于旧生代这种清除量少的情况。

4.分代收集算法:将前三中算法结合,新生代这种存活率较小的情况用复制算法,持久代和旧生代使用其它三种算法。

垃圾收集器是具体地垃圾收集工具,通常考虑并发、垃圾吞吐量、处理时间等情况。垃圾收集器较多,没有进行专门研究。

  6.JVM内存调优

内存调优时由于GC之后内存占用值会发生变化,常使用jdk提供的jmc和jvisualvm进行性能调优。

对jvm内存调优的目的主要针对垃圾回收的频率和full GC的次数来进行的。

1.堆设置

-Xms:初始堆大小

-Xmx:最大堆大小

-XX:NewSize=n:设置年轻代大小

-XX:NewRatio=n:设置年轻代和年老代的比值。如:为3,表示年轻代与年老代比值为1:3,年轻代占整个年轻代年老代和的1/4

-XX:SurvivorRatio=n:年轻代中Eden区与两个Survivor区的比值。注意Survivor区有两个。如:3,表示Eden:Survivor=3:2,一个Survivor区占整个年轻代的1/5

-XX:MaxPermSize=n:设置持久代大小

2.收集器设置

-XX:+UseSerialGC:设置串行收集器

-XX:+UseParallelGC:设置并行收集器

-XX:+UseParalledlOldGC:设置并行年老代收集器

-XX:+UseConcMarkSweepGC:设置并发收集器

3.垃圾回收统计信息

-XX:+PrintGC

-XX:+PrintGCDetails

-XX:+PrintGCTimeStamps

-Xloggc:filename

4.并行收集器设置

-XX:ParallelGCThreads=n:设置并行收集器收集时使用的CPU数。并行收集线程数。

-XX:MaxGCPauseMillis=n:设置并行收集最大暂停时间

-XX:GCTimeRatio=n:设置垃圾回收时间占程序运行时间的百分比。公式为1/(1+n)

5.并发收集器设置

-XX:+CMSIncrementalMode:设置为增量模式。适用于单CPU情况。

-XX:ParallelGCThreads=n:设置并发收集器年轻代收集方式为并行收集时,使用的CPU数。并行收集线程数。


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值