JVM

一、JVM体系结构

Java栈、本地方法栈、程序计数器:线程私有(每个线程拥有一份)、内存很小,几乎不存在垃圾回收

方法区、堆:线程共享(一个进程中只有一份)

二、类加载器(ClassLoader)

class文件开头有特定的标识——cafe.babe

1)类加载器分为四类(面试答前三个就好):

1、启动类加载器:启动就加载rt.jar

2、扩展类加载器:加载jre\lib\ext文件夹下的jar包,包的名字为javax.xxx.xxx

3、应用程序类记载器

4、自定义类加载器

代码案例

public class MyObject {
    public static void main(String[] args) {
        Object object = new Object();
        System.out.println(object.getClass().getClassLoader().getParent().getParent());//Exception in thread "main" java.lang.NullPointerException
        System.out.println(object.getClass().getClassLoader().getParent());//Exception in thread "main" java.lang.NullPointerException
        System.out.println(object.getClass().getClassLoader());//null
        System.out.println("========================");
        MyObject myObject = new MyObject();
        System.out.println(myObject.getClass().getClassLoader().getParent().getParent());//null
        System.out.println(myObject.getClass().getClassLoader().getParent());//sun.misc.Launcher$ExtClassLoader@4554617c
        System.out.println(myObject.getClass().getClassLoader());//sun.misc.Launcher$AppClassLoader@18b4aac2
    }
}

2)双亲委派机制:要加载类,先根据包名类名逐级往上请求,BootStrap->Extension->AppClassLoader

3)沙箱安全机制:防止自定义代码污染到Java源代码

-

运行报错:在类java.lang.String中找不到main方法

三、本地方法栈、本地方法接口(native)

线程、进程不是语言级的,是操作系统级别的。

本地方法栈是为虚拟机使用到native关键字定义的方法服务的,如果是普通方法就放Java栈,如果是native定义的方法就放本地方法栈,native方法实现交给底层的函数库

Thread t1 = new Thread();
t1.start();
t1.start();

运行报错:Exception in thread "main" java.lang.IllegalThreadStateException,不合法的多线程运行状态

public synchronized void start() {
        /**
         * This method is not invoked for the main method thread or "system"
         * group threads created/set up by the VM. Any new functionality added
         * to this method in the future may have to also be added to the VM.
         *
         * A zero status value corresponds to state "NEW".
         */
        if (threadStatus != 0)
            throw new IllegalThreadStateException();

        /* Notify the group that this thread is about to be started
         * so that it can be added to the group's list of threads
         * and the group's unstarted count can be decremented. */
        group.add(this);

        boolean started = false;
        try {
            start0();
            started = true;
        } finally {
            try {
                if (!started) {
                    group.threadStartFailed(this);
                }
            } catch (Throwable ignore) {
                /* do nothing. If start0 threw a Throwable then
                  it will be passed up the call stack */
            }
        }
    }
private native void start0();

四、程序(PC)寄存器

五、方法区

方法区供线程共享,它存储每一个类的结构信息,例如:常量池、字段(静态变量)、方法数据、构造函数和普通方法的字节码内容

PS:实例变量存储在堆内存中,和方法区无关。方法区是一个规范,类似于接口,其落地实现是Java8的元空间或Java7之前的持久代。

六、Java栈(重点

栈管运行,堆管存储

1、栈保存8种基本类型的变量+对象的引用变量+实例方法

2、Java栈中会创建栈帧来存储方法

栈帧中主要保存3类数据:

1)本地变量:输入参数(形参)、输出参数(return数据)、方法内的变量

2)栈操作:记录出栈和入栈的操作

3)栈帧数据:包括类文件(定义在方法内的局部内部类)、方法等

这不是异常,这是错误。。。

HotSpot=JDK       cmd打java -version

元数据=Class=类的结构信息

七、堆(重点

1、堆从物理上分为新生代和老年代

逻辑上分为新生代、老年代、元空间(Java8)

Java8以后的元空间并不在虚拟机中而是使用本机物理内存

堆内存的初始值默认是物理内存的1/64、最大值是是物理内存的1/4

public class Heap {
    public static void main(String[] args) {
        //查看CPU的核数
        System.out.println(Runtime.getRuntime().availableProcessors());
        //最大可以使用内存
        long maxMemory = Runtime.getRuntime().maxMemory();
        //初始默认内存
        long totalMemory = Runtime.getRuntime().totalMemory();
        System.out.println("-Xmx:MAX_MEMORY=" + maxMemory + "(字节)" + (maxMemory / 1024 / 1024) + "MB");
        System.out.println("-Xms:TOTAL_MEMORY=" + totalMemory + "(字节)" + (totalMemory / 1024 / 1024) + "MB");
    }
}

运行结果:

配置堆内存:一般将默认内存大小跟最大可使用内存配置一样大

-Xms——start

-Xmx——max

运行结果:

演示堆内存溢出(OOM):先将堆内存改为10MB方便演示,然后运行下面代码

public class Heap {
    public static void main(String[] args) {
        String str = "hello world";
        while (true) {
            str += str + new Random().nextInt(888888)+ new Random().nextInt(999999999);
        }
        //byte[] bytes = new byte[40*1024*1024];//40MB
    }
}

运行结果:

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
	at java.util.Arrays.copyOf(Arrays.java:3332)
	at java.lang.AbstractStringBuilder.expandCapacity(AbstractStringBuilder.java:137)
	at java.lang.AbstractStringBuilder.ensureCapacityInternal(AbstractStringBuilder.java:121)
	at java.lang.AbstractStringBuilder.append(AbstractStringBuilder.java:647)
	at java.lang.StringBuilder.append(StringBuilder.java:208)
	at cn.wyu.jvm.Heap.main(Heap.java:14)

GC是什么(分代收集算法):没有最好的GC算法,分代,分情况考虑

1)次数上频繁收集Young区

2)次数上较少收集Old区

3)基本不动元空间

Java在进行GC的时候并非每次都对上面三个内存区域一起回收的,大部分时候都回收的是新生代

因此GC又分为两种类型:一种是普通的GC(minor GC)负责回收新生代,一种是全局GC(Full GC)负责回收老年代

minor GC和Full GC的区别:

minor GC回收的速度一般比Full GC快10倍以上,因为新生代空间与老年代空间的大小比是1:2,也就是说新生代空间小。

 

GC四大算法

1)引用计数法

2)复制算法

新生代特点:区域相对较小,对象存活率低

新生代使用的minor GC,这种GC算法采用的是复制算法,不会产生内存碎片,但是耗内存,如果to区满了话,移动到老年区

 

3)标记清除

老年代特点:区域较大,对象存活率高

老年代一般是使用标记清除或者是标记清除与标记压缩整合的算法

原理:

优点:节省空间

缺点:效率比复制算法慢,会产生内存碎片

4)标记压缩

优点:没有内存碎片

缺点:耗时最长


基本类型传的是复印件,引用类型传的是内存地址

案例笔试题:

public class TestTransferValue {
    public void changeValue1(int age){
        age = 30;
    }
    public void changeValue2(Person person){
        person.setPersonName("xxx");

    }
    public void changeValue3(String str){
        str="xxx";
    }
    public static void main(String[] args) {
        TestTransferValue test = new TestTransferValue();
        int age = 20;
        test.changeValue1(age);
        System.out.println("age===="+age);

        Person person = new Person();
        test.changeValue2(person);
        System.out.println("personName===="+person.getPersonName());

        String str = "abc";
        test.changeValue3(str);
        System.out.println("String===="+str);
    }
}


class Person{
    private String personName;

    public String getPersonName() {
        return personName;
    }

    public void setPersonName(String personName) {
        this.personName = personName;
    }
}

运行结果:

图形理解 :

八、JMM

1、volatile是Java虚拟机提供的轻量级的同步机制,只保证可见性、不保证原子性、禁止指令重排

2、JMM的特性:

1)可见性

2)原子性

3)有序性

可见性代码演示:

class MyNumber{
    volatile int number = 10;
    public void addTo1024(){
        this.number = 1024;
    }
}
public class Heap {
    public static void main(String[] args) {
        MyNumber myNumber = new MyNumber();
        new Thread(() ->{
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            myNumber.addTo1024();
            System.out.println(Thread.currentThread().getName()+"\t"+myNumber.number);
        },"AA").start();
        while (myNumber.number == 10){
            //需要有通知机制,告诉main线程,number变成1024了,跳出循环
        }
        System.out.println(Thread.currentThread().getName()+"over");
    }
}

运行结果:

如果不加volition,main线程将在while里面一直循环,跳不出来

运行结果:

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值