JVM一

初入JVM:

什么是JVM:
JVM(Java Virtual Machine,Java虚拟机)。
JVM是JRE的一部分。它是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来实现的。JVM有自己完善的硬件架构,如处理器、堆栈、寄存器等,还具有相应的指令系统。Java语言最重要的特点就是跨平台运行。使用JVM就是为了支持与操作系统无关,实现跨平台。所以,JAVA虚拟机JVM是属于JRE的,而现在我们安装JDK时也附带安装了JRE(当然也可以单独安装JRE)。

JVM在操作系统之上
JVM一_第1张图片JVM一_第2张图片
类加载器:

作用:加载Class文件 ;

JVM中的类加载器主要有四种:
1.虚拟机自带的加载器
2.启动类加载器 BootstrapClassLoader
3.扩展类加载器ExtClassLoader
4.应用程序加载器AppClassLoader

创建实例与返回类加载器

public class Car {
     
    public static void main(String[] args) {
     
        //类是模板,对象是具体的
        //名字在栈里面,实例真正 的数据在堆里面,通过地址去找对应的数据
        //实例化三个对象
        Car car1 = new Car();
        Car car2 = new Car();
        Car car3 = new Car();
        System.out.println(car1.hashCode());//668386784
        System.out.println(car2.hashCode());//1329552164
        System.out.println(car3.hashCode());//363771819
        //返回类相当于返回模板
        Class<? extends Car> aClass1 = car1.getClass();
        Class<? extends Car> aClass2 = car2.getClass();
        Class<? extends Car> aClass3 = car3.getClass();
        //返回的都是同一个类,hashCode值也一样
        System.out.println(aClass1);//class cn.third.code.code13ClassLoader.Car
        System.out.println(aClass2);//class cn.third.code.code13ClassLoader.Car
        System.out.println(aClass3);//class cn.third.code.code13ClassLoader.Car
        System.out.println(aClass1.hashCode());
        System.out.println(aClass2.hashCode());
        System.out.println(aClass3.hashCode());
        /*
        * 类加载器有一种父子关系,处理引导加载器之外,每个类加载器都有一个父类加载器
        * 1.虚拟机自带的加载器  2.启动类加载器  3.扩展类加载器  4.应用程序加载器
        * */
        ClassLoader classLoader = aClass1.getClassLoader();//获取类加载器
        System.out.println(classLoader);//$AppClassLoader  应用程序加载器
        System.out.println(classLoader.getParent());//获取父类加载器 $PlatformClassLoader
        System.out.println(classLoader.getParent().getParent());//null  java调用不到

    }
}

假如我们想自己建一个在java.lang包下的一个String类,并且在类里创建方法并且调用。由于类加载有双亲委派机制,程序运行会报错
双亲委派机制:
加粗样式
当某个类加载器需要加载某个.class文件时,它首先把这个任务委托给他的上级类加载器,递归这个操作,如果上级的类加载器没有加载,自己才会去加载这个类。

在JVM中的类加载器中原本有java.lang包下的String类,系统会自动调用原本系统下的String类,在这个String类下,找不到main方法的

JVM一_第3张图片双亲委派机制的作用

1、防止重复加载同一个.class。通过委托去向上面问一问,加载过了,就不用再加载一遍。保证数据安全。

2、保证核心.class不能被篡改。通过委托方式,不会去篡改核心.clas,即使篡改也不会去加载,即使加载也不会是同一个.class对象了。不同的加载器加载同一个.class也不是同一个Class对象。这样保证了Class执行安全。

JVM内存模型:
JVM一_第4张图片PC寄存器:

每一个线程都有一个程序计数器,是线程私有的
占用内存极小,基本不会发生OOM

native关键字:
凡是带了native关键字的,说明java的作用范围达不到了,回去调用底层C语言的库,会进入本地方法栈,调用本地方法本地接(JNI)
JNI的作用:扩展Java的使用,融合不同的编程语言为Java所用

方法区:
在java8以前,方法区的实现主要是堆中的“永久区”,在java8之后,方法区的具体实现就是在“元空间”,主要存储类的元信息
方法区被所有线程共享,所有字段和方法字节码,以及一些特殊方法,如构造函数、接口代码也在这里定义。
简单说,所有定义的方法的信息都保存在该区域,此区域属于共享区间。
静态变量、常量、类信息(构造方法、接口定义)、运行时的常量池存在方法区中,但是实例变量存在堆内存中,与方法区无关

Java栈:
Java栈又称为虚拟机栈,描述方法执行的内存模型。在每个方法执行的同时会创建一个栈帧,用于存储局部变量表、操作数栈、动态连接、方法出口等信息。每一个方法调用执行完成,都对应着一个栈帧在虚拟机中入栈到出栈的过程。
虚拟机栈的大小默认是1M。

堆:
一个JVM只有一个堆,堆内存的大小是可以调节的。
java8以前,堆内存还细分为三个区域:
新生代:
老年代:
永久代:
Java7及以前版本的Hotspot中方法区位于永久代中。同时,永久代和堆是相互隔离的,但它们使用的物理内存是连续的。 永久代的垃圾收集是和老年代捆绑在一起的,因此无论谁满了,都会触发永久代和老年代的垃圾收集。
永久代( PermGen space ):堆内存的一块逻辑区域。
元空间(Metaspace):元空间和永久代的最大区别就是, 元空间不再与堆连续, 不在虚拟机中,而是直接使用的本地内存( 直接内存是调用native方法分配的内存,不属于JVM管理的内存 )。可以通过以下参数来指定元空间的大小;

//返回虚拟机试图使用的最大内存
        long max = Runtime.getRuntime().maxMemory();
        //返回JVM的初始化总内存
        long total = Runtime.getRuntime().totalMemory();

        System.out.println("max="+max+"字节\t"+(max/(double)1024/1024)+"Mb");//max=1035993088字节	988.0Mb
        System.out.println("total="+total+"字节\t"+(total/(double)1024/1024)+"Mb");//total=65011712字节	62.0Mb

堆内存最大值,默认内存大小:电脑系统运行内存d1/4
堆内存初始大小,默认内存大小:系统1/64
如何调优:
设置最大值和最小值相等(防止内存抖动)
设置成物理内存的1/32(阿里的规范)
使用工具查看元空间大小:visualVM,arthas

为什么元空间要替代永久代:

1。避免oom 。因为通常使用PermSize和MaxPermSize设置永久代的大小就决定了永久代的上限,但是不是总能知道应该设置为多大合适, 如果使用默认值很容易遇到OOM错误。
2. gc算法。

设定堆大小命令:(-Xmx内存大小(m) -Xms内存大小(m) -XX:-UseGCOverheadLimit)

堆区先线程共享的区域,存放的是java中的实例对象。
JVM一_第5张图片Java8以后,堆中分为新生代、老年代、元空间
新生代中主要是伊甸园区、幸存to区、幸存from区,占堆内存的1/3
比例8:1:1
空的一定是to区

老年代占堆内存的2/3
GC算法:
判断对象是死是活:可达性分析法
标记清除算法:
分标记和清除两个步骤,先把要清除的对象标记,标记完后清除。
缺点:效率不高,容易产生内存碎片

复制算法:
将内存分为相等的两份,只用一份存放创建的对象,将要保留的对象复制到另一份空的内存中,然后再全部清除原来的半份
缺点:利用率不高
新生代使用,因为新生代的存活率很低

标记整理算法:
将要清除的对象标记,保留的对象往一端移动,最后清除掉边界外的要清除的对象。
老年代使用。
尽量避免重GC。

你可能感兴趣的:(JVM,jvm)