JVM:java虚拟机 能识别.class文件,并且能够解析他的指令,最终调用操作系统上的函数,完成对应的操作
JRE: Java运行时环境,JVM标准上加上实现的一大堆基础类库 就组成了JRE
JDK:除了包含JRE,提供了一些工具 javac(编译)jar(打包)java p(反编译)
JVM的区域划分虚拟机栈:在JVM运行过程中存储当前线程运行方法所需的数据,指令,返回地址(存储java方法运行)
本地方法栈:本地方法栈是和虚拟机栈非常相似的一个区域,他的服务对象是native方法
程序计数器:主要用来记录各个线程执行的字节码地址(记录运行到耳朵位置)
方法区:存放类的信息、常量池、方法数据、方法代码、静态资源
堆: 堆是JVM上最大的内存区域,我们申请的几乎所有的对象,都是在堆中存储
堆空间大小和划分划分 活跃数据300M*4 总堆1.2G 大厂(京东阿里)划分标准
新生代 3老年代 5永久代 2 堆
Heap一个JVM只有一个堆内存,所有的GC算法都是对堆进行操作的
新生区
类:诞生和成长的地方 甚至死亡伊甸园区
所有的对象都是在这个区new出来的 满了会触发轻GC 幸存0区 幸存1区
老年代 old
永久代 Perm
存储java运行时的一些环境,这个区域不存在垃圾回收,关闭JVM是会释放这个区域的内存一个启动类加载了大量的第三方jar包,Tomcat部署了太多的应用,大量动态生成的反射类都会导致永久区崩溃名字
jdk1.6 :永久代,常量池在方法区jdk1.7 : 永久代,去永久代 常量池在堆中jdk1.8 : 无永久代,常量池在元空间 如何判断一个对象是否存活
引用计数法:
对每个对象加一个计数器,当出现引用是+1 ,取消引用-1 这个方法看似没有问题,但是当出现互相引用时就会出现bug
可达性分析算法:
如图在Java技术体系中,固定可以作为GC Roots的对象有以下几种
在虚拟机栈中引用的对象,如各个线程被调用的方法堆栈中使用到的参数、局部变量、临时变量等
在方法区中类静态属性引用的对象,Java类的引用类型静态变量
在方法区中常量引用的对象,如字符串常量池里的引用
在本地方法栈中JNI(Native方法)引用的对象
Java虚拟机内部的引用,如基本数据类型对应的Class对象,一些常驻的异常对象(NullPointExcepiton、OutOfMemoryError)和系统类加载器
所有被同步锁持有的对象
、
Java中的引用JDK1.2之后 对引用进行了扩充 强引用、软引用、弱引用、虚引用四种 强度依次递减
强引用:传统的引用定义 ,代码中普遍存在的引用Object object = new Object(); 强引用类型只要关系存在就不会被GC处理软引用: 用来描述有些还有用,但非必须的对象。当系统内存溢出异常钱,会把这些对象列入被回收范围之中进行二次回收。 在JDK 1.2版之后提供了SoftReference类来实现软引用弱引用: 同样是非必须对象,但是他的强度比软引用更弱一些,只能生存到下一次垃圾回收发生为止,在进行GC时无论内存是否够用都会清楚掉弱引用对象。在JDK 1.2版之后提供了WeakReference类来实现弱引用。虚引用: 最弱的引用关系,一个对象是否有虚引用的存在,完全不会对其生存时间构成影响,也无法通过虚引用来去的一个对象实例。为一个对象设置虚引用关联的唯一目的只是为了能再这个对象被收集器回收时收到一个系统通知。在JDK 1.2版之后提供 了PhantomReference类来实现虚引用。 JVM 进行GC
JVM在进行GC时,并不是对这三个区域统一回收,大部分时候,回收都是新生代
新生代幸存区老年区
GC两种:轻GC,重GC
GC算法:
标记清除
对存活的对象进行标记,清除没有标记的对象(死亡对象)优点:不需要额外的空间缺点: 两次扫描(第一次标记,第二次清除)严重浪费时间,会产生内存碎片 标记整理
对标记清除再次扫描,想一段移动存活的对象缺点:多了一个移动成本优点:可以避免内存碎片的产生 复制算法 主要在新生区使用
两个幸存区来回翻转如果一个对象经过15次GC后没有被清理就会进入老年区 可以设计进入老年区GC的次数优点: 没有内存碎片缺点:浪费内存空间(多了一半空间是空的) 对对象存活率高的程序不友好 引用计数器
对对象的引用进行计数
总结
内存效率:复制算法>标记清除算法>标记压缩算法
内存整齐度: 复制算法=标记压缩算法>标记清除算法
内存利用率: 标记压缩算法=标记清除算法>复制算法
使用场景
年轻代
存活率低 使用复制算法比较合适



