jvm类加载机制:
加载----验证---准备----解析----初始化----使用-----卸载
一、java的理解
1、平台无关性
2、GC:垃圾回收机制,不用手动释放堆内存
3、语言特性:泛型,反射,lemda表达式
4、面向对象:封装、继承、多态
5、类库:并发库,集合,网络库,IO,NIO
6、异常处理:运行时异常、编译时异常
二、JVM如何加载.class文件
1.1、类从编译到执行的过程:
1、编译器将.java源文件编译为.class字节码文件
2、ClassLoader将字节码文件转换为JVM中的Class<T>对象
3、JVM利用Class<T>对象实例化为T对象。
1.2、ClassLoad的种类:
ClassLoader在java中非常重要,所有Class都是有类加载器进行加载的,作用就是从系统外部获得Class二进制流,交给Java虚拟机进行连接,初始化等操作。
1、BootStrapClassLoader:C++编写,加载核心库java.*
2、ExtClassLoader:Java编写,加载扩展库javax.*
3、AppClassLoader:Java编写,加载程序所在目录。加载类路径下(ClassPath)的类库
4、自定义类加载器:通过继承 java.lang.ClassLoader 。通过指定的Path,去找到文件,之后将文件的二进制流读入程序中。
1.3、双亲委派机制:避免多份同样字节码的加载
1.4、类的加载方式
隐式加载:new
显示加载:loadClass,forName等。
loadClass,forName的区别:Class.forName得到的class是已经初始化完成的,Class.loadClass得到的class是还没有链接的
Spring的IOC,资源加载器获取要读入的资源后,获取bean,要使用loadClass,快速完成类的加载,属性在需要使用的地方再进行初始化
1.5、类的装载过程
三、java的内存模型
3.1、线程的内存模型
程序计数器:
当前线程所执行的字节码行号指示器(逻辑),
改变计数器的值来获取下一条要执行的字节码指令,
和线程是一对一的关系即"线程私有",对java方法计数,
如果是native方法则计数器值为Undefined,
不会发生内存泄漏
虚拟机栈:
java方法执行的内存模型
包含多个栈帧,每个方法在执行的同时都要创建一个栈帧,用于存储局部变量表,操作数栈、动态链接、方法出口等信息
局部变量表:包括方法执行过程中的所有变量
操作数栈:入栈、出栈、复制、交换、产生消费变量。
本地方法栈:
与虚拟机栈相似、主要用于标注了native的方法。
元空间(MetaSpace)与永久代(PermGen)的区别:
1.6之前常量池是在永久代中,当被撑爆时会产生OutOfMemoryError异常,常量池1.7之后,将常量池放到了堆中,避免了此异常出现,1.8之后元空间代替了永久代 。
二者都是对方法区的实现
元空间使用本地内存,永久代使用的是jvm的内存,元空间没有常量池,1.7之后移动到了堆中
1、字符串常量池存在永久代中,容易出现性能问题和内存溢出,
2、类和方法的信息大小难易确定,给永久代的大小指定带来困难,
3、永久代会为GC带来不必要的复杂性,
4、方便HotSpot与其他JVM如Jrockit的集成。
四、java堆(Heap)
所有线程共享的一个内存,对象的分配区域。GC管理的主要区域,新生代,老年代
五、jvm的三大性能调优参数-Xms-Xmx-Xss的含义
-Xss:规定了每个线程虚拟机栈(堆栈)的大小
-Xms:堆的初始值,一般设置和最大值相同,因为当heap扩容时,会产生内存抖动,影响程序运行的稳定性
-Xmx:java堆可扩展的最大值。
六、堆和栈的区别====内存分配策略
静态存储:编译时期确定每个数据目标在运行时的存储空间需求
栈式存储:数据区需求在编译时未知,运行时模块入口前确定。
堆式存储:编译时或运行时模块入口都无法确定,动态分配
堆和栈的区别:
联系:引用对象、数组时,栈里定义变量保存堆中目标的首地址
大方向区别:
管理方式:栈自动释放,堆需要GC
空间大小:栈比堆小
碎片相关:栈产生的碎片远小于堆
分配方式:栈支持静态和动态分配,而堆仅支持动态分配
效率:栈的效率比堆高
大白话区别:
栈内存:程序是在栈内存中运行,占中存的是基本数据类型和堆中对象的引用,栈是运行时的单元(程序是如何执行,或者如何处理数据),一个线程一个独立的线程栈
堆内存:程序运行所需要的大部分数据保存在栈内存中,堆中存储的是对象,堆是存储单元,堆是一块共享的内存,堆解决的是数据存储问题(数据怎么放,放在哪),所有线程共享堆内存