JVM 基础

Jvm下分为这几个部分,以下是对部分的解释

1.pc

  较小的内存空间,线程所执行的字节码行号指示器,由于jvm的多线程是通过轮流切换并分配处理器执行方式实现的,一个处理器只会执行一条指令,每条线程都有独立的计数器,各条线程之间pc互不影响,独立存储,我们称这类内存区域为"线程私有内存"。

2.java stack

  线程私有,执行的同时会创建一个栈帧,用于存储局部变量表,操作数栈,,局部变量表存放了编译期各种数据类型,不等同于对象本省,指向对象起始地址的指针,也可能代表对象句柄或returnAddress类型。在jvm中,如果线程请求的深度大于虚拟机允许的深度,将抛出StackOverflowStack异常,也如果规范内存超出,包出outofMeomery异常

3.native stack

  为虚拟的native方法服务,

4.JAVA堆

  是gc管理的主要区域,从内存回收价值来看,主要采用分代收集算法,堆中细分为新生代,老年代,也可以分诶Eden空间,From Surviour空间etc,主要特点为线程共享,线程共享可以将堆划分为多个私有的分配缓冲区,存储的仍然是对象实例,在规定中,堆可以处于物理上不连续的内存空间中.

5.方法区

  是各个线程的共享内存区域,用于存储一杯虚拟机加载的类信息,常量,静态变量,他有个别名,non-Heap,目的是与java堆分开

6.RCP

  运行常量池是方法区的一部分,信息是常量池,主要用于存放编译器生成的各个字面量和符号引用,虚拟机堆class每一部分都有严格的规定,每一个字节用于存储哪种数据都要符合规范上的需求,

  在rcp与class常量池中特点在于具备动态性,java并不要求常量只有编译期产,并非置于class文件中的常量池才能进入方法区运行的常量池,主要被利用在string类中的intern()方法

7.直接内存

  在jdk1.4 加入的io类,引入了基于通道与缓冲区的i/o方式,可以使用NATIVE函数库直接分配内存,这样可以避免java堆和native堆来回复制数据

    GC

  1.来源于1960Lisp,内存动态分配和垃圾收集技术

2.引用计数算法

  通过给对象引用计数器,每当一个地方引用时,计数器+1从而确认jvm中对象的存在

3.可达性分析算法

  也可与通过可达性分析来确认对象的存活,通过一系列“gc root”做为起始点,从节点向下检索,搜索的路径称为“引用链”当一个对象没有rc引用时则说明对象不可用,在gc root的对象分为几种

  (1)虚拟机栈中引用的对象

  (2)方法区类静态饮用的对象

  (3)方法区中常量引用对象

  (4)本地方法栈中jni对象

4.回收方法区

  方法区惊醒gc效率比较低,在堆中尤其是新生代,常规应用进行一个gc一般可以回收70%-95%的空间,而永久代的垃圾收集效率远低于此

  永久袋垃圾收集主要回收以下内容:废弃常量和无用的类,满足以下条件则可以称为"无用的类"

    (1)该类所有实例回收,但 java堆中不存在该类的实例

    (2)加载该类的classLoader已经被回收

    (3)该类对应的java.lang.class对象没有地方被引用,无法通过任何地方反射方法

  而虚拟机用此方式堆无用类进行回收:-xnoclassge实现

5.垃圾收集算法

  5.1 标记清除算法(Mark-Sweep)

    通过标记需要回收的对象,在标记完成后统一回收,但是存在以下不足

    (1)效率不高

    (2)空间问题,m-s会产生大量不连续的碎片,这会导致运行过程中需要分配大量对象,无法找到内存而提前触发下一步动作

  5.2 复制算法(copying)

    将内存按容量划分为两个等同的块,通过堆半区进行回收,不会担心碎片问题,只要移动指针,按顺序分配内存,代价是将内存缩小到原来的一半。现代商业虚拟机通过此方法进行回收,将内存分为eden空间和Survivor空间,当回收时,存货对象将复制到另外一个surviour空间,但当内存不够时,需要依赖其他内存进行分配内存任务,但当对象存活率较高时会进行大量的复制操作,导致性能下降,所以老年代一般不选用这个方法

  5.3 标记整理算法(Mark-Compact)

    后续不直接对回收对象进行清理,而是将所有存货对象都像后端移动,直接清理边界意外的内存。

  5.4分代收集算法(Generation Collection)

    根据对象存活时期进行划分,根据各个年代进行适当的收集算法。

6.收集器

  收集器是垃圾回收的具体表现

  6.1Serial

  发展最悠久的收集器,在jdk1.3之前做为新生代的唯一收集器,是一个单线程收集器,在垃圾收集时,需要暂停所有工作线程,直到收集结束,她有着以下优点,  

  (1)简单高效,对于但线程环境中,Serial没有线程交互的开销,可以获得最高的单线程收集效率,适用于client模式的虚拟机

  6.2ParNew收集器

  Serial多线程版本,适用于Server模式可以与cms(Concurrent Mask Sweep),实现在用户工作时进行同时工作,但是cms作为老年代的收集器无法与jdk1.4的Paraalel Seavenge配合工作

  并行(Parallel)多条垃圾收集线程工作,但此时用户线程处于等待状态

  并发(Cncurrent):用户线程与gc同时运行

  6.3Parallel Scavenge收集器

    新生代收集器,也是复制算法的收集器,使用目的是达到一个可控制的吞吐量(cpu运行代码与cpu消耗时间的比值)=(吞吐量=运行用户代码时间/(运行代码时间+垃圾收集时间)

    Ps收集器提供了两个参数进行控制: -xx:maxGCPauseMillis 停顿时间,-xx:GCTimeRatio设置吞吐量大小.

  6.4Serial Old

    老年代单线程收集器,使用“m-c”算法,主要用于给client模式使用

  6.5parallel Old

    老年代的收集器,使用多线程和"m-s"算法

  6.6cms

    以获得最短回收停顿为目标的收集器,使用过程分为4个步骤

    1.初始标记(CMS inital Mask)

    2.并发标记(CMS concurrent Mask)

    3.重新标记(CMS remaek)

    4.并发清除(CMD concurrent sweep)

  并发执行清理给用户工作时带来效率,但也存在着以下缺点

  1.对cpu敏感

    由于进行并发处理时通过占用cpu进行工作会导致应用程序变慢,吞吐量降低。

  2.无法处理浮动垃圾(floating Garbage)

    在jdk1.5默认cms使用了68%时空间被激活,这表明着在既要有足够的内存空间给用户使用也要保证垃圾收集时空间进行处理,而无法及时清理的垃圾被称为"浮动垃圾".在jdk1.6中,cmd启动阀值被更改为92%,要是内存无法满足内存需要则会曝出concurrent mode failure失败,这种情况虚拟机会采取应急方案,启动serial old 进行处理,反而导致性能降低

  3.cmd基于m-s算法,这说明会产生大量的碎片无法清理导致内存空间不足。

  6.7G1收集器

    g1是面向服务器端应用的gc,具有以下特点

    1.并行和并发

    2.分代收集

    3.空间整合

    4.可预测的停顿

   g1大概分为以下步骤

  1.初始标记

   2.并发标记

  3.最终标记

  4.筛选回收

7.内存分配策略

     对象的内存分配,就是在堆中分配,对象主要分配在Eden区中,如果启动了本地线程分配缓冲,

  

    

原文地址:https://www.cnblogs.com/EraserHead/p/6441289.html