JVM内存结构及垃圾回收相关

JVM内存结构

主要是看jvm的运行时数据区

运行时数据区主要分为5个部分:

  1. 方法区
  2. 堆区
  3. 虚拟机栈
  4. 本地方法栈
  5. 程序计数器
    运行时数据区

1、方法区

这个区主要存放一些 类型信息、域信息、方法信息、JIT即时编译代码缓存 和 运行时的常量。

该区在jdk7及之前,是包含在JVM内存中的一部分,叫永久代(PermGen)。
在jdk7之后,就把这一块移到了JVM内存之外,变成了元空间(MetaSpace)。不受JVM内存控制,只受机器本身的内存限制。可以设置区域的内存大小。

2、堆区

这个区域存放所有的 对象 信息。
该区域可以分为两部分:年轻代 和 老年代。
年轻代又可以分为:Eden区 、 Survivor0区(简称S0区) 和 Survivor1区(简称S1区)。
具体划分如下图:
堆区
默认内存大小比例:
年轻代:老年代=1:2
Eden:Survivor0:Survivor1=8:1:1

当对象在创建时,首先先放入到Eden区。如果出现了大对象,Eden区内存不够容乃该对象时,考虑直接放入 老年代。
当Eden区内存不够时,会先尝试将对象放入S0区域中,如果S0也内存不足,则进行一次Minor GC(YoungGC/年轻代GC)。此时将存活对象由Eden区域 和 S0区 放入到S1区。如果S0区中有对象存活时间大于了最大存活时间的阈值(threshold),则将该对象晋升到老年代中。
当老年代内存也到达预警内存大小时,则会进行Full GC(MajorGC/全局GC)。此时会回收堆中所有区域。如果FullGC之后还放不下对象时,就会报OOM。
FullGC时,需要Stop the World,所以此时会对程序运行有较大停顿。避免频繁的FullGC也是程序需要优化的一个很关键的点。

3、虚拟机栈区

虚拟机栈区中是一个一个的栈,栈中是一个一个的栈帧。一个虚拟机栈对应的是一个线程,一个栈帧对应的是一个方法。
虚拟机栈
栈帧中包含:局部变量表、操作数栈、方法返回地址、动态链接 和 一些附加的信息。
局部变量表: 主要保存函数的参数以及局部的变量信息。
操作数栈:可以理解为一个用于计算的临时存储数据的区域。
方法返回地址:存放调用该方法的PC寄存器(程序计数器)的值,方法在退出时会去找程序计数器,然后进行下一步的调用。
动态链接:由于java语言的多态性,有些变量在运行期间才会确定下来具体属于哪个类。所以这个动态链接就是指向当前变量或者对象真正的类。
附加信息:栈帧中还允许携带与java虚拟机实现相关的一些附加信息。例如,对程序调试提供支持的信息。

4、程序计数器

记录程序执行的顺序,可以看做是当前线程所执行的字节码的行号指示器。

5、本地方法栈

存放一些本地(native)方法,便于JVM程序调用。

GC(垃圾回收)

垃圾回收的算法
垃圾确认算法: 引用计数法 和 可达性分析算法
垃圾回收算法: 复制算法、标记清除算法、标记压缩算法、分代收集算法、增量收集算法、分区算法
7种垃圾回收器:SerialGC、SerialOldGC、ParNewGC、ParallelGC、ParallelOldGC、CMS、G1。
如图中所示,实线部分是可以配合使用的,虚线部分是之前可以配合使用,之后去除掉不可以配合使用的。
垃圾回收器及之间的配合适用

1、SerialGC 和 SerialOldGC 串行回收器

串行回收器,采用复制算法,适用于单CPU的机器,在没有线程切换的时候,回收效率比较高。
SerialGC是主要针对年轻代的回收。
SerialOldGC是回收老年代的垃圾回收器。

2、ParNewGC 并行回收器

一种支持多线程的垃圾回收器,采用复制算法,在多核机器中使用,能更好的体现多核的高效性。运行效率比串行的更好一些。

3、ParallelGC 和 ParallelOldGC 并行回收器

一个适用于年轻代一个适用于老年代。
ParallelGC 采用复制算法,并行回收机制。
ParallelOldGC 采用标记压缩算法,并行回收机制。
与ParNew相比,达到了 可控制吞吐量 和 自适应调节策略。

4、CMS (Concurrent Mark Sweep)并发垃圾回收

实现了最小停顿垃圾回收。

1、初始标记

只标记GC Roots直接指向的对象。需要Stop-the-World。

2、并发标记

通过GCRoots初始标记一次垃圾。不需要Stop-the-World。

3、重新标记

最终再标记一次不被引用的对象。主要是重新扫描之前并发处理阶段的所有残留更新对象。不需要Stop-the-World。

4、并发回收

与正常程序一起并发执行,不需要Stop-the-World,减少了系统停顿时间,但是吞吐量会稍微有所下降。

5、G1 分区垃圾回收器

G1与其他4个都不同。G1垃圾回收把堆区分为了很多个小的区域,每个区域的存储对象是不定的。一个区域可能现在存的是年轻代的对象,等下次回收之后,可能存的就是老年代的对象。
存储和回收都是分块的进行,可预测可控的停顿时间。在实现较短停顿时间的同时,可以对应用程序有较小的影响。
面向服务端应用,针对具有大内存、多处理器的机器。

一些零碎知识点

1、双亲委派机制:
类加载流程:

1)如果一个类加载器收到了类加载请求,它并不会自己先去加载,而是把这个请求委托给父类的加载器去执行;
2)如果父类加载器还存在其父类加载器,则进一步向上委托,依次递归请求最终将到达顶层的启动类加载器;
3)如果父类加载器可以完成类加载任务,就成功返回,倘若父类加载器无法完成此加载任务,子加载器才会尝试自己去加载,这就是双亲委派模式。

优点

避免类的重复加载
保护程序安全,避免核心API被篡改

2、栈顶缓存技术

将栈顶元素全部缓存在物理CPU的寄存器中,以此降低对内存的读/写次数,提升执行引擎的执行效率。

3、空间分配担保

在发生MinorGC之前,虚拟机会检查老年代的最大可用连续空间是否大于新生代所有对象的总空间。
如果大于,则此次MinorGC是安全的。
如果小于,则看是否开启了空间分配担保。
如果开启了,就会检查 老年代最大可用连续空间 是否大于 历次晋升到老年代的对象的平均大小。
如果大于,则尝试进行一次MinorGC,此次MinorGC是有风险的。
如果小于,则进行一次FullGC。
如果没有开启空间分配担保,则直接进行FullGC。

4、逃逸分析

分析栈帧中的对象或者变量是否只在当前方法中使用。
如果只在当前方法中使用,则没有发生逃逸。否则发生了逃逸。

5、栈上分配 、 标量替换 、同步省略

当对象或者变量没有发生逃逸的时候,会使用栈上分配和标量替换进行优化。

栈上分配

将堆分配转化为栈分配。如果一个对象在子程序中被分配,要使指向该对象的指针永远不会逃逸,对象可能是栈分配的候选,而不是堆分配。

同步省略(锁消除)

如果一个对象被发现只能从一个线程被访问到,那么对于这个对象的操作可以不考虑同步。

分离对象或标量替换

有的对象可能不需要作为一个连续的内存结构存在也可以被访问到,那么对象的部分(或全部)可以不存储在内存,而是存储在CPU寄存器中。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值