1、JVM 的位置
存在操作系统(Windows、Linux、,Mac)上,JRE包含JVM,操作系统存在于硬件系统(Inter、Spac)上,Java程序在JVM运行
2、JVM 的体系结构
Java à Class File à 类加载器(Class Loader)à运行时数据区(Runtime Data Area)也就是虚拟机:
方法区(Method Area):
Java栈(Stack):
本地方法区(Native Method Stack):
堆(Heap:JVM中99%调优的地方):
程序计数器:
à另外,执行引擎,本地方法接口(本地方法库)
3、类加载器(Class Loader)
作用:加载Class文件,类是模板,对象是具体的实例
应用程序加载器 à 扩展类加载器 à 启动类(根)加载器 à 虚拟机自带的加载器
4、双亲委派机制:安全:APP à EXC à BOOT (最终执行) ,
类加载器收到类的请求,将这个请求委托给父类加载器去完成,一直向上委托,直到启动类加载器,启动加载器检查是否可以加载当前类,能加载就结束,否则抛出异常,通知子加载器进行加载,重复检查操作(class not found)
5、沙箱安全机制
基本组件:字节码校验器与类装载器
类装载器:防止恶意代码去干涉善意的代码,保护被信任类的边界,将代码归入保护域,确认代码可以执行哪些操作,包括存储控制器和安全管理器
6、Native
Native:凡是带native关键字的,说明java的作用范围达不到了,回去调用底层C语言的库,会进去本地方法栈调用本地方法本地接口 JNI(扩展java的使用,融合不同的的编程语言为java所用),它在内存区域中专门开辟了一块标记区域:Navtive Method Stac,登记native方法,在最终执行的时候加载本地方法库中的方法通过JNI
应用区域:程序驱动打印机,管理系统
7、PC 寄存器(程序计数器)与方法区与三种JVM(Sun公司、)
每个线程都有一个程序计数器,线程私有的,就是一个指针,内存空间极小,忽略不计
方法区: 静态变量、常量。类信息(构造方法、接口定义)、运行时的常量池存在方法区中,但是实例变量存在堆的内存中,和方法区无关
JVM :Sun公司、BEA、IBM
8、栈(数据结构):先进后出,后进先出(原型:桶)
队列:先进先出(FIFO:first input first ouput)
栈内存:主管程序的运行,生命周期和线程同步,线程技术,栈内存也就释放,对于栈来说,不存在垃圾回收问题,一旦线程结束,栈就over了
栈内存:八大基本类型+对象引用+实例的方法
栈运行原理:栈帧,程序正在执行的方法,一定在栈的最顶部
栈溢出异常:
java.lang.StackOverflowError (-Xms8m -Xmx8m -XX:+PrintGCDetails)
栈+堆+方法区关系:栈中放引用(new Student),堆中放对象具体的实例,实例中的常量去常量池中获取,常量池在方法区中
9、堆与堆内存调优
Heap:一个JVM只有一个堆内存,堆内存的大小是可以调节的
存放内容:类,方法,常量,变量~,保存我们所有引用类型的真是对象
三个区域:GC 垃圾回收主要在伊甸园区与养老区
新生区(Young/New):类诞生和死亡的地方,伊甸园区(new出来的地方)、幸存区(0,1),轻量级GC
养老区(Old):重GC(Full GC)
永久区(Perm):JDK8之后,改名叫元空间,JDK1.6之前为永久代,常量池在方法区,JDK1.8之后,无永久代,常量池在元空间(逻辑上存在,物理上不存在)
内存满了异常:OOM,内存不足(java.lang.OutOfMemoryError)
OOM 排查错误:( 默认情况下,分配内存是电脑内存的:1/4,而初始内存为:1/64**)**
第一步:尝试扩大堆内存看结果
调整分配内存,并打印GC内存细节:-Xms1024m -Xmx1024m -XX:+PrintGCDetails
第二步:分析内存,专业工具(内存快照分析工具:JProfilter/MAT)排查问题具体地方
分析工具:分析Dump文件,快速定位内存泄漏,获取堆中数据,获取大的对象
VM 参数导出Dump文件:-Xms1m -Xmx8m -XX:+HeapDumpOnOutOfMemoryError
分析当前对象集与想成存储,定位错误的位置
参数: -Xms初始化内存,-Xmx最大分配内存,-XX:+PrintGCDetails打印垃圾回收信息,-XX:+HeapDumpOnOutOfMemoryError文件Dump(oom)
10、GC (轻GC-普通,重GC-全局)
常用算法:
引用计数法、
复制算法 (幸存区0与1,设置GC次数进入老年区),好处没有内存碎片,坏处但浪费内存空间,多了一半空间永远为to
标记清除算法 (一次扫描标记活着的对象,一次扫描清除没有标记的对象),好处不需要额外的空间,坏处是两次扫描,浪费时间,产生内存碎片
标记压缩算法 :防止内存碎片产生,(三次扫描)再次扫描,移动一段存活的对象
总结:
内存效率:复制算法>标记清除算法>标记压缩算法
内存整齐度:复制算法=标记压缩算法>标记清除算法
内存利用率:标记压缩算法>标记清除算法>复制算法
年轻代:存活率低,用复制算法
老年代:区域大,存活率,标记清除(内存碎片不是太多)+标记压缩混合 实现