jvm3

来源:互联网 发布:如何屏蔽淘宝短信 编辑:程序博客网 时间:2024/05/21 19:49
package com;


public class Jvm2 {

/**
* 根据类型创建对象

* 程序计数器:当前线程所执行的字节码的行号指示器,若执行native方法,则指示器为null;若执行java方法,则记录的是jvm字节码指令的地址

* 虚拟机栈:描述java方法执行的内存模型,每个方法执行时都会创建一个栈帧,用于存储局部变量表,操作数栈,动态链接,方法出口等信息,方法的执行过程对应着栈帧在jvm中入栈到出栈的过程
局部变量表:存放了编译期可知的各种数据类型(8个),对象引用,returnAddress类型(也是指向了一条字节码指令的地址)

* 本地方法栈:描述执行native方法的内存模型,为jvm使用到的native方法提供服务的

* 堆:存放对象实例

* 方法区:用于存储已被jvm加载的类信息,常量,静态变量,即时编译器编译后的代码数据

* 新生对象分配内存:
1:指针碰撞:若java堆内存规整,用过的放一边,没用过的放一边,中间放一个指针作为分界点,若创建对象就移动指针即可(Servial,ParNew,)
2:空闲列表:若java内存不规整,则jvm就必须维护一个列表,记录那些内存是可用的,在分配时从列表中找到一块足够大的空间划分为对象实例,并更新列表(CMS)
* 采用哪种分配方式由java堆是否规整决定,而java堆是否规整又由所采用的垃圾收集算法是否带有压缩整理功能决定

* 对象的访问定位
栈------>堆
1:使用句柄:java堆中将会划分出一块内存来作为句柄池,reference中存储的就是对象的句柄地址,而句柄中包含了对象实例数据与类型数据各自的具体地址信息(对象移动只改变句柄池的地址)
2:直接指针:reference中直接存储的就是对象的地址(JVM采用)(速度快,节省开销)

*/

/*
1:判断对象是否存活?
a:引用计数算法:给对象添加一个引用计数器,每当有一个地方引用它时,计数器加一,当引用失效时,计数器减一,当
该对象的引用计数器为0时,我们认为该对象就不能被使用了
特点:效率高,但是无法解决循环引用的问题(即A引用B,B引用A)
b:正向可达算法:以一个“GC Roots”为根节点,从这个节点往下搜索,搜索走过的路径称为引用链,当一个对象到GC Roots
没有任何引用链时,就证明此对象是不可用的
可作为“GC Roots”的对象有:
1:虚拟机栈中引用的对象
2:本地方法栈中引用的对象
3:方法区中类的静态属性引用的对象
4:方法区中常量引用的对象

2:引用分类
a:强引用(Strong Reference),Object o = new Object(),只要强引用还在,JVM就不会回收该对象
b:软引用(Soft Reference),描述还有用但非必须的对象,在JVM发生内存溢出之前,会对这些对象进行回收
c:弱引用(Weak Reference),被弱应用关联的对象只能生存到下一次JVM垃圾收集之前
d:虚引用(Phantom Reference),一个对象是否有虚引用,安全不会对它的生存时间构成影响,也无法通过虚引用取得一个对象
       的实例,为一个对象设置虚引用的唯一目的就是在这个对象呗收集器回收时收到一个系统通知
       
3:生存还是死亡
即使在正向可达算法中不可达的对象,也并非是非死不可的,此时它处于“缓刑”阶段,真正宣告一个对象死亡至少需要2次标记过程
第一次:没有到“GC Roots”的引用链,对它进行第一次标记,并且进行一次筛选,筛选的条件是此对象是否有必要执行finalize()
方法,当对象没有覆盖finalize()方法,或此方法已经被JVM调用过,则认为“没有必要执行”;如果此对象被认为有必要执行finalize()
方法,那么此对象就会被放在一个F-Queue的队列,这个队列是由一个低优先级的Finalizer线程去执行,稍后GC将对F-Queue中的对象
进行对二次小规模标记,如果对象在finalize()中自救(与“GC Roots”建链就可以),那么该对象就活了,没有自救,就会被回收了

4:垃圾收集算法
a:标记清除算法(Mark-Sweep):首先标记处所有需要回收的对象,然后统一回收所有标记的对象
不足:
1 :效率低
2:标记清除后会产生大量不连续的内存碎片,碎片太多会导致为大对象分配内存时,因无法找到足够的连续内存而不得不提前触发一次垃圾收动作
b:复制算法(Copying),解决效率问题:将内存按容量划分为大小相等的两块,每次只使用其中的一块,当一块用完,就把还存活的对象复制到另外一块上,
再把上一块内存清理干净,大多数的JVM都采用这种算法回收新生代;
将内存分为一块较大的Eden区和两块较小的Survivor区,每次使用Eden和其中一块Survivor,HotSpot默认的Eden和Survivor大小比例是8:1;即每次只
浪费10%,当Survivor空间不够用时,需要依赖其他内存(老年代)进行分配担保
c:标记整理算法(Mark-compact);把存活的对象往一端压缩(替换位置),然后清理掉可回收的对象

d:分代收集算法:JVM所采用的算法,即把内存分为新生代和老年代,新生代采取复制算法,老年代采用标记压缩或标记算法


5:垃圾收集器(新生代的收集器和老年代的收集器配合使用,但是G1收集器不需要搭配使用)没有最好的收集器,只要更适合的收集器
新生代收集器包括:Serial收集器,ParNew收集器,Parallel Scavenge(pai ruo low,死ga run zhi)收集器
老年代收集器包括:Serial Old收集器,CMS收集器,Paraller Old收集器
a:Serial收集器:单线程收集器,即只会使用一个CPU或一条收集线程去完成垃圾收集,且它进行垃圾收集时,必须暂停其他所有的工作线程,
直到它收集结束;但他仍然是jvm运行在Client模式下默认的新生代的收集器
b:ParNew收集器:其实就是Serial收集器的多线程版本,即使用多条线程进行垃圾收集,它是在Server模式下首选的新生代垃圾收集器

并发:指用户线程与垃圾收集线程同时执行(但不一定是并行的,可能会交替执行),用户程序在继续运行,而垃圾收集程序运行于另一个CPU上
并行:指多条垃圾收集线程并行工作,但此时用户线程仍然处于等待状态

c:Parallel Scavenge收集器:并行的多线程收集器,它关注的点是达到一个可控制的吞吐量;而像CMS收集器关注的是尽可能缩短垃圾收集时用户
线程的停顿时间

d:Serial Old收集器:是Serial收集器的老年代版本,也是一个单线程的收集器,使用“标记-整理”算法;也是给Client模式下的虚拟机使用的
e:Parallel Old收集器:是Parallel Scavenge收集器的老年代版本,在注重吞吐量和CPU资源敏感的场合可以优先考虑
f:CMS收集器:一种获取最短回收停顿时间为目标的收集器(停顿时间最短),响应速度快,基于“标记-清除”算法
g:G1收集器:面向服务端应用的垃圾收集器
特点:1:并行与并发。2:分代收集。3:空间整合。4:可预测的停顿

6:对象分配问题
a:对象优先在Eden分配,当Eden区没有足够的空间进行分配时,虚拟机将进行一次Minor GC(发生在新生代的垃圾收集)
老年代GC("Major GC/Full GC",出现了Major GC,经常会伴随至少一次的Minor GC)
b:大对象直接进入老年代,大对象是指需要大量连续内存空间的Java对象,最典型的大对象就是那种很长的字符串以及数组
c:长期存活的对象将进入老年代,虚拟机给每个对象定义了一个对象年龄(Age)计数器,如果对象在Eden出生且经过一次Minor GC存活
且被Survivor容纳,此时对象年龄设为1,对象熬过一次“Minor GC”,年龄就增加1岁,当年龄到达一定的程度(默认15,可调),就会被晋升到
老年代。
d:动态对象年龄判断,如果Survivor空间中相同年龄所有对象大小的总和大于Survivor空间的一半,年龄大于或等于该年龄的对象就可以直接进入
老年代,无需等到15岁
e:空间分配担保:把Survivor无法容纳的对象直接进入老年代

 */
}
原创粉丝点击