java虚拟机
JVM HotSpot
JVM体系结构

类加载器
作用:加载Class文件
1.虚拟机自带的加载器 2.启动类加载器 3.扩展类加载器 4.应用程序加载器
双亲委派机制:
类加载器收到类加载的请求,将这个请求向上委托给父类加载器,一直向上委托
启动加载器检查是否能加载当前这个类,能加载就结束,使用当前加载器,否则抛出异常,通知子加载器进行加载
沙箱机制
字节码校验器:确保java类文件遵循语言规范。
类装载器:1.防止恶意代码去干涉代码;双亲委派机制2.守护了被信任的类库边界3.将代码归入保护域,确定了代码能进行什么操作
native
凡是带了native关键字的,说明java的作用范围达不到了,回去调用底层的c语言的库
进入本地方法栈,调用本地方法接口JNI
JNI:扩展java的使用,融合不同的编程语言为java所用
Native Method Stack:登记native方法,在最终执行的时候通过JNI调用本地方法库
程序计数器
程序计数器(Program Counter Register)是一块较小的内存空间,它可以看作是当前线程所执行的字节
码的行号指示器。在虚拟机的概念模型里(仅是概念模型,各种虚拟机可能会通过一些更高效的方式去实现)
字节码解释器工作时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令,分支、循环跳转、
异常处理、线程恢复等基础功能都需要依赖这个计数器赖完成。
方法区
方法区是被所有线程共享的,所有的字段和方法字节码以及一些特殊的方法,都在此定义,次区域属于共享区间。
静态变量、常量、类信息、运行时的常量池存在方法区中,实例变量存在堆内存中,和方法区无关
Jdk1.8之后被元空间所代替
堆
Heap,一个jvm只有一个堆内存,堆内存的大小是可以调节的
堆中主要存放的就是实例化后的数据,类,方法,常量,变量,所有引用类型的真实对象
三个区域
新生区
类所实例化的对象:诞生、成长、死亡的地方
伊甸园区:所有的对象都是在这new出来的,如果这里满了就会产生一次轻量级GC,幸存者会存到新生区中的幸存区 eden
幸存0区 from或to
幸存1区 to或from 谁空谁是to
当幸存区满了后会触发重量级GC,活下来的会存到养老区(默认一个对象经历了15次GC)
养老区paroldgen
永久区(元空间)metaspace
常驻内存区域,存放jdk自身携带的class对象,存储的是java运行时的一些环境或类信息,这个区域不存在垃圾回收,关闭虚拟机就会释放这个区域的内存
jdk1.6之前:永久代,常量池在方法区中
jdk1.7 :永久代,但是慢慢退化了,去永久代,常量池在堆中
jdk1.8之后:无永久代,常量池在元空间
逻辑上存在,物理上不存在
OOM
1.尝试扩大堆内存看结果
-Xms1024m -Xmx1024m -XX:+PrintGCDetails
2.分析内存,看下哪个地方出现了问题
使用Jprofiler工具
-Xms1m -Xmx8m -XX:+HeapDumpOnOutofMemoryError
GC:垃圾回收
引用计数法:需要给每个对象分配一个计数器,计算使用次数,计数器也需要消耗内存(jvm不采用)
GC常用算法
复制算法
Survivor区,一块叫From,一块叫To,对象存在Eden和From块。当进行GC时,Eden存活的对象全移到To块,而From中,存活的对象按年龄值确定去向,当达到一定值(年龄阈值,通过-XX:MaxTenuringThreshold可设置)的对象会移到年老代中,没有达到值的复制到To区,经过GC后,Eden和From被清空。
之后,From和To交换角色,新的From即为原来的To块,新的To块即为原来的From块,且新的To块中对象年龄加1
没有内存碎片但多了一半空间永远是空的to(为了保证能够复制到一个地方),并且存在极端情况全部存活的时候需要全部复制
标记清除算法
扫描对象:对对象进行标记
清除:对没有标记的对象进行清除
两次扫描严重浪费时间会产生内存碎片,不需要额外的空间
标记压缩清除算法
压缩:防止内存碎片,再次扫描,向一端移动存活的对象,多了移动成本

浙公网安备 33010602011771号