jvm
- java文件通过javac编译成class文件
- class文件通过类装载器加载和解密
- 类装载器分为:
根装载器
扩展装载器
应用程序装载器
自定义装载器 - 双亲委派机制:
类装载的时候先去应用程序装载器找有没有加载过这个类,如果没有,再去找扩展装载器有没有加载过这个类,如果没有,再去找根装载器有没有加载过这个类,如果都不存在,从根装载器开始判断是否能加载这个类,如果不能,就在往下判断扩展装载器是够能加载这个类,依次到应用程序装载器。
总结就是:向上查找,向下加载 - 沙箱安全机制:
1.减少外来代码带来的不安全隐患,通过双亲委派机制实现
2.增加保护域对外来代码进行信任认证
jvm包含
- 方法区
存放static final Class模板(构造方法 接口定义) 运行时的常量池 - 堆
存放实际的对象,实例变量,对象的属性值指向方法区。对象引用结束,就要回收对象,垃圾回收gc。内存分为四个区域:新生区,幸存区(from和to),老年区,永久区。垃圾回收主要在新生区和养老区。新生区回收叫做轻gc,养老区回收叫重gc - 栈
存放八大基本类型,对象的引用(地址),实例的方法。主管程序的运行,生命周期和线程同步,线程结束,栈内存释放。不存在垃圾回收 - 本地方法栈
调用本地方法接口(JNI) - 程序计数器(pc寄存器)
表示指针计数,例如对线程编号,占用空间很小,用完即释放
如何定位堆内存溢出(OOM)
- 内存快照分析工具,MAT、Jprofiler
-Jprofiler功能:idea下的工具
分析内存Dump文件,快速定位内存泄露
获得堆中的数据
获取大的对象
idea设置:
-XX:+PrintGCDetails 打印GC垃圾回收信息
-XX:+HeapDumpOnOutOfMemoryError
打印内存溢出Dump文件 - 一行一行debug代码(不现实)
GC的方法:
- 标记清除法
扫描对象,对需要存活对象(可达性算法)进行标记,再次扫描对象,清除没有被标记的对象
优点:
不浪费内存空间
缺点:
两次扫描严重浪费时间,清除对象后内存碎片化 - 标记压缩
对标记清除法的缺点进行优化。
再次扫描,向一端移动存活的对象,防止内存碎片产生。
缺点:
又一次扫描浪费时间,移动对象浪费时间。
优化:
可以五次标记清除之后做一次压缩。 - 复制算法:
主要总在新生区。每次gc都会把新生区的对象移到幸存区,幸存区分为from和to区,如果两个区都有数据,复制算法就会把from中的对象转移到to区,然后to区变成from区,from区变成to区,保证to区一直是空的。一个对象经过了15次gc还没有死,就会进入老年区,次数可设置-XX:MaxTenuringThreshold=5
好处:
没有内存的碎片
坏处:
浪费内存空间,一个幸存区to的空间,极端情况下对象百分百存活,每次都要复制全部对象,浪费时间和内存
最佳适用场景:对象存活度较低的时候-新生区 - 引用计数法(逐渐淘汰)
总结:
- 内存效率:复制>标记清除>标记压缩
- 内存整齐度:复制=标记压缩>标记清除
- 内存利用率:标记清除=标记压缩>复制
- 没有最好的算法,只有最合适的算法。
- GC又被称为分代收集算法:
新生代:存活率低 用复制算法
老年代:存活率高 用标记清除+标记压缩