JVM是什么
JVM包括一套字节码指令集、一组寄存器、一个栈、一个垃圾回收堆和一个存储方法域,他屏蔽了底层的操作系统技术,让我们的java程序生成了在java虚拟上的字节码文件(.class),因此java可以跨平台使用。
JVM有什么
PC寄存器
存储了每个线程下一步要做的事情
JVM栈
JVM栈是线程私有的,每个线程都会创建JVM栈,栈里存放了局部基本类型的变量(int等)。
堆
存储里所有对象
- 堆内存都是线程共享的,因此每次申请对象都需要申请锁资源,在线程上增加了TLAB,相当于线程缓存区,因此每个线程申请资源时,都会先申请自身线程的资源。
- 新创建的对象基本都会存在于新生代区域,除了对象足够大。活的够久的对象会被存放在老年代。
运行时常量池
存储了运行中的常量信息、方法和field的引用信息。
方法区域
存储了类的信息,静态变量、静态常量、类中的方法信息等,一定条件下也会被gc的。
本地方法堆栈
存放了运行时的方法的调用状态
垃圾回收
判断对象是否可用的两种常用方法
引用计数算法:给对象中添加一个引用计数器,当一个地方引用了该对象,计数器加1,当一个地方没有引用该对象,计数器减1
根对象可达法:从根对象向下遍历,当无法遍历到则证明该对象无法被引用。
垃圾收集算法
- 标记-清除法:分为标记和清除两个阶段,将对象标记后进行清除
优点: 算法简单
缺点: 清楚后会留下大量的内存碎片
- 复制算法: 将一块内存分为A和B两块区域,只有一片区域负责内存的存储,当需要清理时,将所有不需要清除的对象复制到另一片区域,清理之前的空间。
优点:不会留下内存碎片
缺点:内存空间利用率过低
- 标记-整理算法 : 将所有需要清除的对象清除后,将剩余的对象向一侧移动。
优点: 解决了内存碎片的问题 缺点:移动麻烦
- 分代收集算法
这种是目前java常用的垃圾收集算法
根据对象特性将对象分为新生代和老年代和元空间(方法区-持久代)(在新的版本中已经将永久代废弃,引入了元空间的概念,永久代使用的是JVM内存而元空间直接使用物理内存)
因此我们可以根据不同的方法对对象进行处理。
新生代 : 分为Eden:Survivor from : Survivor to = 8:1:1 ,由于新生代的对象生命周期很短,所以新生代采用复制算法。
老年代 : 老年代的对象由于存活周期长,一般使用标记清除或者标记整理算法
新生代的对象会先去Eden区,当Eden区满了会去Survivor from区,当两个区域都满了后会进行一次Minor GC,将Eden和Survivor from copy到Survivor to区,再清空Eden区和Survivor from区域,这时候 from区会变为to 区,如果Survivor from区无法容纳全部的对象,则会根据老年代的分配担保策略存入老年代,如果老年代也无法容纳则会进行full GC。
什么时候进入到老年代
1、根据参数,大对象直接进入老年代。 2、长期存活的对象进入老年代:每一个对象刚创建时都会有一个年龄,每次minorGC 都会给年龄加1,默认到达15岁则升级为老年代,如果Survivor去区中相同年龄所有对象大小的总和大于Survivor区的一半,则大于等于这个年龄的对象会晋升至老年代。
- 对新生代的对象回收称为minorgc
- 对老年代的对象进行回收称为full gc
- 主动gc为full gc
JVM 也会根据不同的对象进行不同的回收策略
- 强引用 : 默认使用这种引用。当对象没被引用时才会回收这种对象
- 软引用 : 当内存不够时会被回收
- 弱引用 : 当gc时一定会被回收
- 虚引用 : 用于引用只是用来得知对象是否gc