Java—JVM

#Java—JVM

1.虚拟机的概念:在软件上模拟具有完全硬件功能的、运行在完全隔离的环境中的计算机系统。

常见的虚拟机 VMware、JVM、Virtual Box等

JVM和VMware、Virtural Box的区别

a.VMWare和Virtual Box是通过软件模拟物理CPU的指令集,物理系统中会有很多的寄存器。

b.JVM是通过软件模拟Java字节码的指令集,JVM中只是主要保留了PC寄存器,对其他寄存器进行了裁剪。

有很多的虚拟机,(JDK8)HotSpot 这个虚拟机是整合了HotSpot和Jrockit VM的优点。

Java内存区域划分:

将Java内存划分成两大区域:

1.线程私有

a.程序计数器:

概念:记录正在执行的线程虚拟机字节码指令的地址,如果正在执行的是一个Native方法,则计数器为空。

可以将它理解为行号计数器。

··为什么要有程序计数器?为什么这个计数器是私有的?

首先,多线程 通过轮流切换并分配处理器的方式来实现,在任何一个时刻,处理器都会执行一个线程的指令。因此为了切换线程后能恢复到正确的执行位置每条线程都需要独立的程序计数器,各自的计数器互不影响。

**b.虚拟机栈:**局部变量表、操作数栈、动态链接、方法出口。

局部变量表:各种基本数据数据类型和对象引用,在编译期间完成分配,在执行期间不会改变局部变量的大小。

产生的异常:

StackOverFlowError :请求栈的深度大于虚拟机锁允许的深度 可以设置(-Xss设置栈的容量)

OutOfMemoryError(OOM):虚拟机在动态扩展的时候无法申请到足够多的的内存

c.本地方法栈:

本地方法栈为虚拟机使用的Native方法服务,而虚拟机栈为JVM执行的Java方法服务

2.线程共享

a.堆GC:是JVM分配内存的最大一块区域。是所有线程共享的一块区域。 对空间可以是不连续的

Java是Java垃圾回收器主要管理的一块内存,所以也叫GC堆,堆容量是可以扩展的(-Xmx设置最大值 -Xms设置最小值)

如果堆中没有足够的空间完成实例的分配并且堆也无法扩展时 抛出OOM异常

b.方法区:

方法区又称永久代在JDK8后被称为 元空间(MetaSpace) 存放 虚拟机加载的类信息、静态变量、常量、编译器编译后的代码。

c.运行时常量池

字面量:字符串(JDK1.7后移到堆中),final常量,基本数据类型的值。

符号引用:类和结构的完全限定名、字段的名称和描述符、方法的名称和描述符。

Java heap OOM

public class Test{
    static class OOMObject{}
    public static void main(String[] args) {
        List<OOMObject> list=new ArrayList<>();
            while(true){
                list.add(new OOMObject());
            }
    }
}

StackOverFlowError:

public class Test{
    private static int num=0;
    public static void main(String[] args) {
        try {
            print();
        }finally {
            System.out.println("栈的深度"+num);
        }
    }
    public static void print(){
        num++;
        print();
    }
}

Java垃圾回收器与内存分配策略

1.如何判断对象已死:

**a.引用计数法:**给对象增加一个引用计数器,每当有一个地方引用它,计数器加1;当引用失效时,计数器减1;任何时候计数器为0,说明对象没有再被使用,此时对象已死。

JVM没有用这个方法,原因是如果有循环引用时,计数器永远都不会减到1,那么对象永远不会被回收

public class Test{
    private Object instance=null;
    public static void main(String[] args) {
        Test test1=new Test();//1
        Test test2=new Test();//2
        test1.instance=test2;//3
        test2.instance=test1;//4
        test1=null;//5
        test2=null;//6
        //强制进行垃圾回收
        System.gc();//7
    }
}

我们来分析上面的代码:

1.test1的计数器 count1=1;

2.test2的计数器,count2=1;

3.test1中的instance引用 test2 所以 test2=2

4.test2中的instance引用test1所以test1=2;

5.6 count1=1 count2=1;

7.System.gc() 注意 这个方法只是触发,什么时候回收由系统调度。

b.可达性分析算法:

通过一系列称为:“GC Roots”的对象作为起始点,从这些节点开始向下搜索,搜索过的路径称为"引用链".当一个对象到GC Roots没有任何引用链连时(从GC Roots到这个对象不可达),证明此事对象是不可用的。

可作为GC Roots的对象:

1.虚拟机栈中引用的对象

2.方法区中静态属性引用的对象

3.方法区常量引用的对象

4.本地方法栈中JNI(Native方法)引用的对象,

JDK1.2之后对Java引用的概念做了扩充,将引用分为四种 强引用(Strong Reference) 软引用(Strong Reference) 弱引用(Weak Reference) 虚引用(Phantom Reference) 强度依次递减

1.强引用:在程序中普遍存在的引用,只要引用还在,这个对象永远不会被回收

2.软引用:描述一些还有但是不是 必须的对象,在系统要发送内存溢出之前,将这类引用列入回收范围,以供第二次回收,如果这次回收空间还是不够,那么抛异常OOM。

3.弱引用:描述非必须的对象,这些对象只能生存到下次gc之前,垃圾回收器开始后无论内存是否够用,都要直接回收。

4.虚引用:一个对象是否由虚引用不会对其生存时间够成影响,也无法通过虚引用来取得一个实例化对象,只会在被gc回收后首到一个系统通知。

finalize方法:

在可达性算法分析对象不可达的对象也不是非死不可的, 它至少要有两次标记过程:如果对象在进行可达性分析之后发现没有GC Roots相连接的引用链,那它会被第一次标记并且进行一次筛选,筛选的条件是此对象是要执行finalize(),当finalize没有被覆盖或者已死已经被JVM调用过了,这时对象才会真正被回收。

回收方法区:

方法区的垃圾回收主要是回收两个部分:无用类和无用常量。

如何判断类是无用类:

a.该类的实例对象都已经被回收(在Java堆中不存在任何该类有关的实例)

b.加载该类的classloaer已经被回收

c.该类对应的Class对象没有任何其他方法被引用,无法在任何地方通过反射访问该方法

注:在大量使用反射、动态代理等场景都需要JVM具备类卸载的功能防止永久代的溢出。

垃圾回收算法

标记—清除算法

复制算法(新生代算法)

标志整理算法(老年代算法)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值