突突英雄

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

JVM:

首先了解一下并行和串行的区别:

并行:未包含用户线程,是有多个GC线程

并发:包含了用户线程,GC与用户线程一起(交替)工作

HotSpot和Client:

HotSpot:最主要的一个特点就是它可以把经常使用的CLASS文件保存在缓存里,这样就提高了JVM的效率。

Client:和HotSpot是两种不同的机制,并不是说是用了两套虚拟机,而是一套虚拟机下不同的两种初始化方法。Client更多的基于桌面级应用而进行内存分配。

关于JVM的一些知识:

(1)类加载子系统与方法区:类加载子系统负责从文件系统或者网络中加载CLASS信息,加载的类信息存放在一块称为方法区的内存空间。除了类的信息外,方法区中还可能会存放运行时的常量池信息,包括字符串字面量和数字常量(这部分信息是CLASS文件中常量池的内存映射)

(2)Java堆:Java堆在虚拟机启动的时候建立,它是Java程序最主要的内存工作区域,几乎所有的Java对象实例都存放在堆区中,堆空间是所有线程共享的,这是一块与Java应用密切相关的内存空间

(3)直接内存:Java的NIO库允许Java使用直接内存,直接内存是在Java堆外的、直接向系统申请的内存空间。通常访问直接内存的速度要快于访问Java堆,因此出于提高性能的考虑,读写频繁的场合可能会考虑使用直接内存,由于直接内存在Java堆外,因此它的大小不会受限于XMX指定的最大堆大小,但是系统内存是有限的,Java堆和直接内存的总和依然受限于操作系统能给出的最大内存。

(4)垃圾回收系统:垃圾回收系统是Java虚拟机的重要组成部分,垃圾回收器可以对方法区、Java堆和直接内存进行回收。其中Java堆是垃圾回收器的工作重点。和C/C++不同,Java中所有对象的空间释放都是隐式的,也就是说Java中没有类似于FREE()、DELETE()这样的方法释放指定的内存区域。

(5)Java栈:每一个Java虚拟机线程都有一个私有的Java栈,一个线程Java栈在一个Java线程创建的时候被创建,其中保存着帧信息,Java栈中保存着局部变量,方法参数,同时和方法的调用返回密切相关。栈帧:当新方法进入栈时,没有运行完的方法就会保存起来,形成栈帧

(6)本地方法栈:和Java栈非常类似,最大的不同就是Java栈用于Java方法的调用,本地方法栈用于本地方法的调用(nativemethod),一般Java程序的运行都离不开操作系统的方法。这也是为什么不同JVM的API不同,因为不同操作系统里有着不同的本地方法。Java虚拟机允许Java直接调用本地方法,一般都是使用C语言编写的。

(7)PC寄存器:PC寄存器也是每一个Java线程私有的空间,Java虚拟机会为每一个线程创建一个PC寄存器,在任意时刻,一个Java线程总是在执行一个方法,这个被执行的方法被称为当前方法,如果正在执行的方法不是本地方法那么PC就会指向当前正在被执行的指令,如果当前方法是本地方法那么PC寄存器的值就是UNDEFINED

(8)执行引擎:执行引擎是Java虚拟机最核心的组件之一,它负责执行字节码,现在的虚拟机为了提高效率,使用即时编译(JUST IN TIME)技术将字节码译成机器码再执行。

JVM堆结构及分代:

Java虚拟机根据对象存活的周期不同,一般将堆内存划分为新生代、老年代、永久代(对于HOTSPOT而言)

分代:堆内存是虚拟机管理的内存中最大的一块,也是垃圾回收最频繁的一块区域,程序的所有对象都放在堆内存中,给堆内存分代是为了提高内存的利用率和垃圾回收的效率。如果不分代各种生命周期的对象杂糅,每次想要找出指定对象的时候都要全部遍历,效率大大降低,分代之后还提高了内存的利用率,而且还可以根据不同代的对象采用更为适合的垃圾回收算法,提高效率,即分代垃圾回收。

新生代:朝生夕死,常规应用进行一次垃圾收集可以回收70%-95%的空间,回收效率很高。HOTSPOT将新生代分为三个部分,一块较大的EDEN区,两块较小的SURVIVOR,默认比例8:1:1,划分的目的是因为HOTSPOT采用复制算法来回收新生代,设置这个比例是为了充分利用内存空间减少浪费,大对象一般直接存在老年代中。新生代中的对象没经过一次垃圾回收年龄加一。

复制算法:当在EDEN区没有足够的空间分配内存时,会调用GC,当调用GC的时候,对象都存在EDEN区和FROM SURVIVOR区中,TO SURVIVOR区中为空,是一块儿保留空间。GC时达到年龄阈值的对象会被复制到老年代中,没有达到阈值的就会被存到TO SURVIVOR中,接着清空EDEN和FROM SURVIVOR,在GC结束后又将TO SURVIVOR 中的对象复制到FROM SURVIVOR中。总之不管怎么样在一轮GC后TO SURVIVOR区都保证是空的。GC时当TO SURVIVOR没有足够的空间存放上一次新生代收集下来的存活对象时,需要依赖老年代进行分配担保,将这些对象放在老年代中。

老年代:在新生代中经历了多次GC后(次数看虚拟机的配置)仍然存活下来的对象,老年代中GC频率较低,回收速度较慢

永久代:永久存储类信息、常量、静态变量、即时编译器编译后的代码等数据,对这一区域而言,JVM不会对其进行GC。

JVM垃圾回收常见的算法:

1、引用计数:当这个对象有引用的时候就给计数器+1,删除引用就-1,致命的缺点就是无法处理循环引用。

2、复制算法:把内存划成两个区域,每次只使用一个区,GC时只处理正在使用的区。复制后还会进行有序的整理,缺点是需要两倍的内存空间

3、标记-清除:分为两个阶段,第一阶段遍历内存,标记被引用的对象,第二阶段遍历内存,回收未标记的对象。GC时会暂停整个应用,并且会产生碎片,也就是会浪费内存。

4、标记-整理:结合了赋值和清除两个算法的优点,也是两个阶段,第一阶段标记被引用的对象,第二阶段时回收未标记的并且按顺序压缩标记的

垃圾收集器与垃圾收集算法

次收集(SCAVENGE GC):当年轻代堆空间紧张时就会触发,触发频繁

全收集(FULL GC):当老年代或持久代堆空间满了会触发全收集操作

SYSTEM.GC()是让FULL GC优先启动

HOTSPOT的七个收集器:

新生代(YOUNG GENERATION)中:SERIAL、PARNEW、PARALLEL SCAVENGE

老年代(TENURED GENERATION):CMS(COUCURRENT MARK SWEEP)、SERIAL OLD、PARALLEL OLD

新老代:G1(GARBAGE FIRST)

SERIAL(串行收集器):特点是只用一条线程进行GC,且需要暂停其他所有的工作线程,所以也称STOP THE WORLD(STW),回收新生代时使用的是复制算法,回收老年代使用的是标记-整理算法

PARNEW(并行收集器):是SERIAL的多线程版本,除了用多个线程进行GC外其他的都与SERIAL一样,是启动CMS后的默认新生代收集器

PARALLEL SCAVENGE:跟PARNEW一样,使用复制算法,也是多线程,PARALLEL SCAVENGE更关注系统吞吐量(运行用户代码时间/(运行用户代码时间+垃圾回收时间))

SERIAL OLD:在老年代里使用的是标记-整理算法,不能再使用复制算法,因为没有空间进行复制。SERIAL OLD兼容性很好,可以和年轻代所有收集器协作使用

PARALLEL OLD:使用多线程和“标记-整理”算法,吞吐量优先,他只能和PARALLEL SCAVENGE配合使用

CMS:特点:GC与用户线程一起(交替)工作

 

监视JVM的工具:jvisualvm 插件gc

JVM参数介绍:

-Xms:初始堆大小

-Xmx:允许申请的最大堆的大小

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

-XX:NewRatio=n:按照多大的比例

-XX:SurvivorRatio=n:Eden区与两个Survivor区的比值

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

收集器:

-XX:+UseSerialGC,虚拟机运行在Client模式下的默认值,Serial+Serial Old。

-XX:+UseParNewGC,ParNew+Serial Old,在JDK1.8被废弃,在JDK1.7还可以使用。

-XX:+UseConcMarkSweepGC,ParNew+CMS+Serial Old

-XX:+UseParallelGC,虚拟机运行在Server模式下的默认值,Parallel Scavenge+Serial Old(PS Mark Sweep)。

-XX:+UseParallelOldGC,Parallel Scavenge+Parallel Old。

-XX:+UseG1GC,G1+G1。

posted on 2019-04-13 09:12  突突英雄  阅读(71)  评论(0编辑  收藏  举报