jvm记录

对JVM的理解?
java8虚拟机有什么更新?
什么是oom?
什么是StackOverflowError?
有哪些方法分析?
JVM常用调优参数?
JVM中,对诶加载器的认识?

JVM体系概述

位置

JVM是运行在操作系统之上的,它与硬件 硬件没有直接的交互。

体系结构

数据区亮色区域线程共享,灰色线程不共享。
 

一、类装载器 ClassLoader

负责加载class文件,class文件内容在开头有特定的文件标识 ,将calss文件字节码内容加载到内存中,并将这些内容转化成方法区中的运行时数据结构并且ClassLoader 只负责class文件的加载,至于它是否可以运行,则由Excution Engine决定。
特定标识:

 分类:

大致可分为四类:

(1)虚拟机自带的加载器

· 启动类加载器(根加载器) Bootstrap  c++编写的

· 扩展类加载器 Extension java编写的

· 应用类加载器(AppClassLoader),加载当前应用的classpath的所有类。

(2)用户自定义加载器

· Java.lang.ClassLoader的子类,用户可以定制类的加载方式。

先来解释下启动类加载器,当程序中有new java自带的类的时候,加载这个文件时,启动类加载器会去加载;而当程序有new 我们自己写的类的时候,加载文件时,应用类加载器会去加载。

public class TEST {
    public static void main(String[] args) {
        // java自带的类
        Object obj = new Object();
        System.out.println(obj.getClass().getClassLoader());
        // 自己写的类
        TEST test = new TEST();
        System.out.println(test.getClass().getClassLoader());
    }
}

打印启动类加载器默认显示的就是null,而打印应用类加载器显示的就是AppClassLoader了

public class TEST {
    public static void main(String[] args) {
        TEST test = new TEST();
        System.out.println(test.getClass().getClassLoader().getParent().getParent()); // 启动类加载器
        System.out.println(test.getClass().getClassLoader().getParent()); // 扩展类加载器
        System.out.println(test.getClass().getClassLoader()); // 应用类加载器
    }
}

什么是ClassLoader的双亲委派机制?

java中为了保证类加载的安全,使用了双亲委派机制,优先从启动类加载器中加载,这个称为"父","父"无法加载到,再从扩展类加载器加载,这个称为 "母",“双亲委派”。如果都加载不到,那么会通过  "应用类加载器" 加载,如果也找不到会报:ClassNotFoundExcption。


 

二、本地接口

三、pc寄存器(程序计数器)

记录方法之间调用和执行情况,它用来指向下一条指令的地址。

 四、方法区

所有线程共享

他存储了每一个类 的结构信息,例如:运行时常量池、字段、方法数据、构造方法和普通方法的字节码文件内容。上边讲的是规范,在不同虚拟机里头实现是不一样的,最典型的就是永久代和元空间。

栈管运行,堆管存储。

五、堆

六、java栈

后进先出,先进后出。

不存在垃圾回收。

栈也叫栈内存,主管java程序的运行,是在线程创建的时候创建,它的生命周期是跟随线程的生命周期,线程结束内存也就释放,对于栈来说,不存在垃圾回收的问题,只要线程一结束,就over,生命周期和线程一致,是线程私有的。8种基本类型的变量 + 对象的引用变量+实例方法都是在函数的栈内存种分配。

栈帧

等于java的方法,只不过在栈中方法为栈帧。

栈存储什么

栈帧中主要存储三类数据:

本地变量:输入和输出参数以及方法内的变量。

栈操作:记录出栈,入栈操作。

栈帧数据:包括类文件、方法等等,

栈运行原理

栈中的数据都是以栈帧(Stack Frame)的格式存在,栈帧是一个内存区块,是一个数据集,是一个有关方法(Method)和运行期数据的数据集。当一个方法A被调用时就产生了一个栈帧F1,并压入到栈中,A方法又调用了B方法,于是又产生了栈帧F2也被压入到栈,B方法又调用了C方法,于是产生了栈帧F3也被压入到栈中··· ···

执行完毕,先弹出F3栈帧,在弹出F1栈帧··· ···

遵循 “先进后出” "后进先出" 的原则。

每个方法执行的同时,都会创建一个栈帧,用于存储局部变量表、操作数栈、动态链接、方法出口等信息,每一个方法从调用直至执行完毕的过程,就对应着一个栈帧在虚拟机中入栈到出栈的过程,栈的大小和具体JVM的实现有关,通常在256K~756K,约等于1M.

栈堆方法区关系

StackOverflowError 异常

栈溢出是一个错误。

heap

OOM:堆内存溢出。

新生代(eden区伊甸区、from区幸存者0区、to幸存者1区)和老年代。

 永久区

 方法区:

 原空间:

 

堆参数调整

 一个16G的内存,默认分配给JVM 堆内存

最大大小为(-Xmx):物理内存的 "1/4" 也就是 16/4 (实际上16G内存只会有 15.4G大小),以15.4G为例,15.4 / 4 = 3.85G; 三个多G就是上限了。

初始值的默认大小为(-Xms):15.4 / 64 = 245M。

public class Lv20210814 {
    public static void main(String[] args) {
        // 返回Java虚拟机试图使用的最大内存值
        long maxMemory = Runtime.getRuntime().maxMemory();
        // 返回Java虚拟机中的内存总量
        long totalMemory = Runtime.getRuntime().totalMemory();
        System.out.println("-Xmx MAX_MEMORY: "+maxMemory+"字节 -> "+(maxMemory / (double) 1024 / 1024) + "MB");
        System.out.println("-Xms TOTAL_MEMORY: "+totalMemory+"字节 -> "+(totalMemory / (double) 1024 / 1024) + "MB");
    }
}

 在实际开发中,一般会调到一样大初始值和最大值,避免GC和应用程序争抢内存。

 

 在idea中调整初始值和最大值

 初始值和最大值都改为10Mb,测试大小自定义

-Xms10m -Xmx10m -XX:+PrintGCDetails

测试堆溢出

创建一个大于10Mb的对象即可

byte[] bytes = new byte[40*1024*1024];

 

 对JVM GC的理解

采用分代收集算法,次数上频繁收集Young区。此时上较少收集Old区,基本不动元空间。

未完成,待续。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值