JVM——Java内存区域相关3

一. 垃圾收集算法

1. 标记-清除算法

缺点:1.效率低,标记和清除两个过程的效率都不高;

2.空间问题,标记清除后会产生大量的不连续内存碎片。

2. 复制算法

将内存分成三块:一块较大的Eden和两块较小的Survivor空间。每次使用Eden和其中一块Survivor,回收后将Eden和Survivor中还存活着的对象一次性的复制到另外一块Survivor空间上。如果复制过程中Survivor的空间不够用时,需要依赖老年代进行分配担保。

3. 标记-整理算法

和标记-清理算法类似,只不过后续步骤不是直接对可回收对象进行清理,而是让所有存货对象都向一边移动,然后直接清理掉端边界以外的内存,这样就保证了没有内存碎片的存在。这种方法比较适合老年代使用。

二. HotSpot的算法实现

1. 枚举根节点

准确式GC(即虚拟机知道哪块内存存放对象的具体类型),为了避免一个不漏的检查完所有执行上下文和全局的引用位置,虚拟机通过一组称为OopMap解决了分辨获取对象类型信息的问题。

2. 安全点

能够改变对象引用的指令非常多,如果针对每一条指令都生成对象的OopMap将会耗费大量的额外空间。为了解决这个问题,虚拟机只在特点的地方——一些“具有让程序长时间执行”的地方(为了将GC控制在一个合适的频率)如方法调用、循环跳转、异常跳转——这些地方被称为Safepoint。

为了同步所有线程,让他们都到达Safepoint之后再统一GC,有两种发放可供选择:

  • 抢先式中断,先把所有线程全部中断,不再安全点上就恢复线程,让它跑到安全点上。
  • 主动式,GC需要中断时设置一个标志,各线程会去主动轮询这个标志,当发现中断标志就自己中断挂起,轮询标志的地方和安全点是重合的。

疑问:为什么不是每次到达安全点再轮询?然后抢先中断方法的恢复线程后让它跑到安全点的过程是否和主动式有些类似??

3. 安全区域

在程序不执行即处于sleep状态或者blocked状态时无法响应JVM的中断请求、“走”到安全点挂起。这时候就需要安全区域(Safe Region)来解决。

Safe Region是指在一段代码片段中引用关系都不会发生变化,在这个区域中的任意地方开始GC都是安全的。在线程执行到Safe Region中的代码时,首先标识自己已经进入了Safe Region,那么当这段时间JVM要发起GC时,就不用管标识自己为Safe Region状态的线程了。在线程要离开Safe Region时,它要检查系统是否已经完成了根节点枚举(或者整个GC过程),如果完成了,那线程就继续执行,否则它就等到直到收到可以安全离开Safe Region的信号为止。

疑问:这个真的解决了线程阻塞而无法响应JVM中断请求的问题吗?

三. 垃圾收集器

1. Serial(new:Serial——old:CMS、Serial Old)

单线程收集器,进行垃圾收集时必须暂停其他所有的工作线程直到它收集结束。

2. ParNew(new:ParNew——old:CMS、Serial Old)

Serial收集器的多线程版本,能与CMS配合工作是选择ParNew的一个重要原因。-XX:ParallelGCThreads参数来限制垃圾收集的线程数。

3. Parallel Scavenge(new:Parallel Scavenge——old:Serial Old、Parallel Old)

CMS等收集器的关注点是尽可能缩短垃圾收集时用户线程的停顿时间,而Parallel Scavenge收集器的目标则是达到一个可控的吞吐量(Throughput)。

停顿时间越短就越适合需要与用户交互的程序,相应更快;高吞吐量则可以高效率的利用CPU时间,尽快完成程序的计算任务。

相关参数

4. Serial Old(new:Serial、ParNew、Parallel Scavenge——old:Serial Old)

单线程收集器。

5. Parallel Old(new:Parallel Scavenge——old:Parallel Old)

在主要吞吐量以及CPU资源敏感的场合,可以优先考虑Parallel Scavenge加Parallel Old收集器组合。

6. CMS(new:Serial、ParNew——old:CMS、Serial Old)

  • 初始标记(stop the world)
  • 并发标记
  • 重新标记(stop the world)
  • 并发清理

缺点:

      • 对CPU资源敏感。在并发阶段,虽然它不会导致用户线程停顿,但是会因为占用了一部分线程(CPU资源)而导致应用程序变慢。
      • CMS无法处理浮动垃圾(Floating Garbage)。因为CMS并发清理阶段用户线程还在运行,所以伴随着程序运行还会有新的垃圾不断产生,这一部分垃圾出现在标记过程之后而只能留待下一次GC时再处理。这部分垃圾就称为浮动垃圾。另外一个相应的后果时CMS不能像其他线程一样等到老年代几乎被完全填满了在进行收集,因为它必须留一部分给垃圾收集时程序运行使用,所以CMS有一个老年代阀值,超过这个阀值就进行收集。
      • CMS是一个基于“标记-清理”算法实现的收集器,会产生内存碎片

7. G1

  • 并发与并行
  • 分代收集
  • 空间整合:基于“标记-清理”,没有内存碎片问题
  • 可预测的停顿:消耗在垃圾收集上的时间不得超过N毫秒

使用G1收集器,Java堆的内存布局就与其他收集器有很大差别,它将整个Java堆划分多个大小相等的独立区域(Region),虽然还保留有新生代和老年代的概念,但新生代和老年代不再是物理隔离的,他们都是一部分Region(不需要连续)的集合。

G1可预测的停顿实现归功于避免进行全区域的垃圾收集。G1每次只收集回报最高的Region。

Region之间的对象引用虚拟机都是使用Rememberd Set来避免全堆扫描的。

时间: 2024-11-05 19:00:27

JVM——Java内存区域相关3的相关文章

JVM——Java内存区域相关2

一. 对象的创建 在语言层面上,创建对象的方式有克隆.反序列化.new等方法. 1.1 检查类是否被加载 虚拟机遇到一条new指令时,首先去检查这个指令的参数是否能够在常量池中定位到一个类的符号引用,并且检查这个符号引用代表的类是否已被加载.解析和初始化过.如果没有,那必须先执行相应的类加载过程. 1.2 分配内存 指针碰撞(Bump the Pointer):同步(CAS或者TLAB),内存碎片问题. 空闲列表(Free List) 1.3 初始化为零值(不包括对象头). 1.4 设置对象信息

JVM——Java内存区域

                                        JVM 一.概念 虚拟机:通过软件模拟的具有完整硬件功能的运行在一个完全隔离环境中的完整操作系统. JVM:软件虚拟Java字节码指令集. HoSpot是Java默认的虚拟机. 二.Java内存区域与内存溢出异常 Java虚拟机所管理的内存包括如下几个运行时数据区域: (1)线程私有区域(随线程的创建与销毁而创建与销毁):程序计数器.虚拟机栈.本地方法栈. (2)线程共有区域:Java堆.方法区.运行时常量池. 1.

jvm java内存区域的介绍

jvm虚拟机在运行时需要用到的内存区域.广泛一点就是堆和栈,其实不然,堆和栈只是相对比较笼统的说法,真正区分有如下几个 先上图一: 总的就是 java的内存模型 内存模型又分堆内存(heap)和方法区(有时也称为non-heap)和栈 堆又分新生代(Young)和老年代(old/Tenured) 新生代又分默认比例为8:1:1的eden空间.from survivor空间.to survivor空间 当进行垃圾回收时,eden.survivor from 存活得对象会复制到servivor to

【java】JVM的内存区域划分

学过C语言的朋友都知道C编译器在划分内存区域的时候经常将管理的区域划分为数据段和代码段,数据段包括堆.栈以及静态数据区.那么在Java语言当中,内存又是如何划分的呢? 由于Java程序是交由JVM执行的,所以我们在谈Java内存区域划分的时候事实上是指JVM内存区域划分.在讨论JVM内存区域划分之前,先来看一下Java程序具体执行的过程: 如上图所示,首先Java源代码文件(.java后缀)会被Java编译器编译为字节码文件(.class后缀),然后由JVM中的类加载器加载各个类的字节码文件,加

JVM高级特性与实践(一):Java内存区域 与 内存溢出异常

对于从事C.C++的开发人员而言,在内存管理领域,他们具有绝对的“权利”——拥有每个对象的控制权,并担负着每个对象生命周期的维护责任.而对于Java开发人员而言,在虚拟机自动内存管理机制的帮助下,无需为每一个创建new操作去配对 delete/free 代码,减少内存泄漏和内存溢出的问题,这些都交给了Java虚拟机去进行内存控制,但是正因如此,当出现相关问题时,若不了解JVM使用内存规则,就难以排查错误.接下来以此篇文章记录学习Java虚拟机内存各个区域概念.作用.服务对象以及可能产生的问题.

JVM系列文章(一):Java内存区域分析

作为一个程序员,仅仅知道怎么用是远远不够的.起码,你需要知道为什么可以这么用,即我们所谓底层的东西. 那到底什么是底层呢?我觉得这不能一概而论.以我现在的知识水平而言:对于Web开发者,TCP/IP.HTTP等等协议可能就是底层:对于C.C++程序员,内存.指针等等可能就是底层的东西.那对于Java开发者,你的Java代码运行所在的JVM可能就是你所需要去了解.理解的东西. 我会在接下来的一段时间,和读者您一起去学习JVM,所有内容均参考自<深入理解Java虚拟机:JVM高级特性与最佳实践>(

学习jvm(一)--java内存区域

前言 通过学习深入理解java虚拟机的教程,以及自己在网上的查询的资料,做一个对jvm学习过程中的小总结. 本文章内容首先讲解java的内存分布区域,之后讲内存的分配原则以及内存的监控工具.再下来会着重讲解垃圾回收这一章节,该章节涉及了垃圾的标记算法以及各种垃圾回收算法,然后大概的介绍下市面上使用的垃圾收集器.之后就总结下上面的原理,讲解相关的jvm调优案例.然后会着重讲解类加载过程.最后一章讲字节码的部分,字节码相对来说是比较枯燥而且特别繁琐的内容,最好是自己动手配合着学习会好一点,或者观其大

【搞定Jvm面试】 Java 内存区域揭秘附常见面试题解析

本文已经收录自笔者开源的 JavaGuide: https://github.com/Snailclimb ([Java学习+面试指南] 一份涵盖大部分Java程序员所需要掌握的核心知识)如果觉得不错的还,不妨去点个Star,鼓励一下! Java 内存区域详解 如果没有特殊说明,都是针对的是 HotSpot 虚拟机. 写在前面 (常见面试题) 基本问题 介绍下 Java 内存区域(运行时数据区) Java 对象的创建过程(五步,建议能默写出来并且要知道每一步虚拟机做了什么) 对象的访问定位的两种

JVM性能优化系列-(1) Java内存区域

1. Java内存区域 1.1 运行时数据区 Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干个不同的数据区域.主要包括:程序计数器.虚拟机栈.本地方法栈.Java堆.方法区(运 行时常量池).直接内存. 程序计数器 程序计数器(Program Counter Register)是一块较小的内存空间,可以看作是当前线程所执行的字节码的行号指示器.在虚拟机概念模型中,字节码解释器工作时就是通过改变计数器的值来选取下一条需要执行的字节码指令,分支.循环.跳转.异常处理.线程恢复等