一、jvm是干什么的?

大家都知道java是跨平台语言,一次编译可以在不同操作系统上运行,怎么做到的呢,看下图:

javac把写的源代码(java文件),编译成字节码(class文件),字节码部署到linux/windows/..上,被对应的jvm解释成机器码运行,jvm的工作就是这个。

大家都知道,java不需要开发者写代码来申请、释放和管理内存,jvm在运行时帮助我们做了这个事情,即便如此,我们还是需要了解jvm的内存结构,以便排查各种和内存有关的问题,比如oom,性能调优。

二、jvm内存结构是怎样的?

Java的兄弟,有没有曾经碰到过这些问题,出现OOM是什么原因?性能慢打dump发现是在等待内存分配,怎么查?了解jvm内存结构,当出现内存相关问题时,便于分析解决问题。

下图比较清晰的展示了jvm内存结构:

1、jvm内存结构分3大块:堆内存Heap、方法区Method Area和栈Stack堆;

2、堆内存Heap:分为年轻代Young Generation和老年代Old Generation;

3、年轻代YG:又分为3部分,Eden Space、From Survivor Space、To Survivor Space.

 再来看看主要的几个参数:

▪ -Xms设置堆的最小空间大小;

▪ -Xmx设置堆的最大空间大小;

▪ -XX:NewSize设置新生代最小空间大小;

▪ -XX:MaxNewSize设置新生代最大空间大小;

▪ -XX:PermSize设置永久代最小空间大小;

▪ -XX:MaxPermSize设置永久代最大空间大小;

▪ -Xss设置每个线程的堆栈大小。

三、各内存空间分别存放一些什么东西,我们写的代码对应了哪些内存空间?

1、堆内存Heap,存的是对象,所有的对象在实例化后的整个运行周期内,都被存放在堆内存中

2、方法区Method Area,存的是已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据

3、栈Stack,存的是基本数据类型和堆中对象的引用

堆内存,又分年轻代和老年代,那么,什么情况下用年轻代,什么情况下会进入老年代呢?

1、运行时,新创建的对象分配在年轻代的Eden,随着时间推移,Eden会满,这时候就会触发MinorGC.

2、有几种情况,会触发对象进入老年代:

1)JVM会给对象增加一个年龄(age)的计数器,对象每“熬过”一次GC,年龄就+1,当年龄达到设置的阈值(默认为15)就会被移到老年代。(可通过-XX:MaxTenuringThreshold调整阈值, 一次Minor GC后,对象年龄就会+1,达到阈值的对象就移动到老年代,其他存活下来的对象会继续保留在新生代中)

2)不用等待15次GC之后进入老年代,大致是,如果一批对象的总大小大于这块Survivor(From/To)内存的50%,那么大于这批对象年龄的对象就进入老年代

3)如果设置了参数-XX:PretenureSizeThreshold,那么如果创建的对象大于这个参数值,就直接把这个对象放入老年代,不经过新生代。这么做就可以避免大对象在新生代,屡次躲过GC,还得把他们来回复制,最后才进入老年代,浪费时间。

四、上面大致了解了内存结构,写的代码JVM是怎么分配内存的,那么什么样的对象用到的内存该回收了,怎么回收呢?

先来看第一个问题,什么样的对象用的内存该回收了?肯定是没用的对象就回收了,要用的对象你千万别给回收了是吧。怎么判断对象没用了,变成垃圾了,下面介绍它的几个算法:

1、引用计数法

在 Java 中,引用和对象是有关联的。如果要操作对象则必须用引用进行。因此,很显然一个简单的办法是通过引用计数来判断一个对象是否可以回收。简单说,即一个对象如果没有任何与之关联的引用,即他们的引用计数都不为0,则说明对象不太可能再被用到,那么这个对象就是可回收对象。 据说此算法存在循环引用问题,欢迎读者朋友们,帮忙留言补充什么是循环引用问题,最好能举例子哦,多谢多谢!

2、可达性分析

为了解决引用计数法的循环引用问题,Java 使用了可达性分析的方法。通过一系列的“GC roots”对象作为起点搜索。如果在“GC roots”和一个对象之间没有可达路径,则称该对象是不可达的。要注意的是,不可达对象不等价于可回收对象,不可达对象变为可回收对象至少要经过两次标记过程。两次标记后仍然是可回收对象,则将面临回收。

上面辨别出来了垃圾,接下来就是要看这些垃圾该怎么回收了:

1、标记清除算法(Mark-Sweep)

最基础的垃圾回收算法,分为两个阶段,标注和清除。标记阶段标记出所有需要回收的对象,清除阶段回收被标记的对象所占用的空间。很明显,这个算法很直接,但会造成碎片是不,来个大对象,可能找不到一块连续的内存空间给她用。

2、复制算法(copying)

为了解决 Mark-Sweep 算法内存碎片化的缺陷而被提出的算法。按内存容量将内存划分为大小一样的两块。每次只使用其中一块,当这一块内存满后将尚存活的对象复制到另一块上去,把已使用 的内存清掉。很直接吧,把上面说有碎片的问题就解决了,但是也有个缺点,内存是不是有点浪费,只能用一半。

3、标记整理算法(Mark-Compact)

结合了以上两个算法,为了避免缺陷而提出。标记阶段和 Mark-Sweep 算法相同,标记后不是清理对象,而是将存活对象集中到内存的一端,再将另外一端清理掉。

4、分代收集算法

分代收集法是目前大部分 JVM 所采用的方法,其核心思想是根据对象存活的不同生命周期将内存 划分为不同的域,一般情况下将 GC 堆划分为老年代(Old Generation)和新生代(Young Generation)。老生代的特点是每次垃圾回收时只有少量对象需要被回收,新生代的特点是每次垃 圾回收时都有大量垃圾需要被回收,因此可以根据不同区域选择不同的算法:

1)新生代,复制算法:每次垃圾收集都能发现大批对象已死,只有少量存活,因此选用复制算法,只需要付出少量存活对象的复制成本就可以完成收集;

2)老年代,标记整理算法:因为对象存活率高,并且没有额外空间对它进行分配担保,就必须采用“标记清理”或“标记整理”算法来进行回收,不必进行内存复制,且直接腾出空闲内存。

下面简单分代收集算法写一下整体是怎么运作的

1)对象的内存分配主要在新生代的 Eden Space 和 Survivor 的From Space(Survivor 目前存放对象的那一块),少数情况会直接分配到老生代;

2)当新生代的 Eden Space 和 From Space 空间不足时就会发生一次GC,GC 后,Eden Space 和 From Space 的存活对象会被挪到 To Space,然后将 Eden Space 和 From Space 进行清理;

3)如果 To Space 无法足够存储某个对象,则将这个对象存储到老年代;

4)在进行 GC 后,使用的便是 Eden Space 和 To Space 了,如此反复循环;

5)当对象在 Survivor 区躲过一次 GC 后,其年龄就会+1。默认情况下年龄到达 15 的对象会被 移到老生代中。

5、分区收集算法

将整个堆空间划分为连续的不同小区间,每个小区间独立使用,独立回收,这样做的好处是可以控制一次回收多少个小区间, 根据目标停顿时间, 每次合理地回收若干个小区间(而不是整个堆), 从而减少一次 GC 所产生的停顿。

 

一文搞懂JVM内存结构+GC的更多相关文章

  1. 一文搞懂jvm内存结构

    一.jvm是干什么的? 大家都知道java是跨平台语言,一次编译可以在不同操作系统上运行,怎么做到的呢,看下图: javac把写的源代码(java文件),编译成字节码(class文件),字节码部署到l ...

  2. Java虚拟机系列一:一文搞懂 JVM 架构和运行时数据区

    前言 之前写博客一直比较随性,主题也很随意,就是想到什么写什么,对什么感兴趣就写什么.虽然写起来无拘无束,自在随意,但也带来了一些问题,每次写完一篇后就要去纠结下一篇到底写什么,看来选择太多也不是好事 ...

  3. 一文看懂JVM内存区域分布与作用

    那么我们在开始介绍Java内存区域之前,我们先放一张内存区域的图,方便我们后面介绍的时候可以对照着看. 须知,本文是根据JDK8来介绍的. 程序计数器 首先它是线程私有的,它也称为代码的行号指示器,字 ...

  4. 举一个有趣的例子,让你轻松搞懂JVM内存管理

    目录 前言 例子 源码 输出 图解 深入分析 学以致用 写在最后 前言 在JAVA虚拟机内存管理中,堆.栈.方法区.常量池等概念经常被提到,对理论知识的理解也常常停留在字面意思上,比如说堆内存中存放对 ...

  5. 管中窥豹——从对象的生命周期梳理JVM内存结构、GC调优、类加载、AOP编程及性能监控

    如题,本文的宗旨既是透过对象的生命周期,来梳理JVM内存结构及GC相关知识,并辅以AOP及双亲委派机制原理,学习不仅仅是海绵式的吸收学习,还需要自己去分析why,加深对技术的理解和认知,祝大家早日走上 ...

  6. 一夜搞懂 | JVM 字节码执行引擎

    前言 本文已经收录到我的 Github 个人博客,欢迎大佬们光临寒舍: 我的 GIthub 博客 学习导图 一.为什么要学习字节码执行引擎? 代码编译的结果从本地机器码转变为字节码,是存储格式发展的一 ...

  7. 一文搞懂所有Java集合面试题

    Java集合 刚刚经历过秋招,看了大量的面经,顺便将常见的Java集合常考知识点总结了一下,并根据被问到的频率大致做了一个标注.一颗星表示知识点需要了解,被问到的频率不高,面试时起码能说个差不多.两颗 ...

  8. 【Java】JMM内存模型和JVM内存结构

    JMM内存模型和JVM内存结构 JAVA内存模型(Java Memory Model) Java内存模型,一般指的是JDK 5 开始使用的新的内存模型,主要由JSR-133: JavaTM Memor ...

  9. jvm系列(二):JVM内存结构

    JVM内存结构 所有的Java开发人员可能会遇到这样的困惑?我该为堆内存设置多大空间呢?OutOfMemoryError的异常到底涉及到运行时数据的哪块区域?该怎么解决呢?其实如果你经常解决服务器性能 ...

随机推荐

  1. 项目课 day02.1

    JWT - json-web-token json.dumps(d,separators = (',' , ':')) separators:分隔符,键值对之间  ,相连, jwt.encode({' ...

  2. Graylog

    Graylog #Graylog 是与 ELK 可以相提并论的一款集中式日志管理方案,支持数据收集.检索.可视化 ​#Graylog 架构 - Graylog 负责接收来自各种设备和应用的日志,并为用 ...

  3. BaseAdapter教程(1) 最简单地使用BaseAdapter

    Adapter就是适配器,而设计模式里也有Adapter Pattern. 而BaseAdapter就是设计模式里的思维,把一些不相关的东西放进去,经过适配器,最终都会出产同一样的东西. 就像Base ...

  4. 吴裕雄--天生自然python机器学习:使用K-近邻算法改进约会网站的配对效果

    在约会网站使用K-近邻算法 准备数据:从文本文件中解析数据 海伦收集约会数据巳经有了一段时间,她把这些数据存放在文本文件(1如1^及抓 比加 中,每 个样本数据占据一行,总共有1000行.海伦的样本主 ...

  5. 用Kinect为听障人士架一座沟通的桥梁

    编者按:这是微软亚洲研究院和中国科学院共同进行的一个合作项目,希望通过使用Kinect来帮助提升手语的识别率,从而为听力受损的残障人士(以下简称听障人士)架起一座与外界沟通的桥梁. 文章译自:Digi ...

  6. Java面试题1-附答案

    List和Set比较,各自的子类比较 对比一:Arraylist与LinkedList的比较 1.ArrayList是实现了基于动态数组的数据结构,因为地址连续,一旦数据存储好了,查询操作效率会比较高 ...

  7. Flask的Jinja2模版过滤器

    Jinja2模版过滤器 过滤器是通过管道符号(|)进行使用的,例如:{{ name|length }},将返回name的长度.过滤器相当于是一个函数,把当前的变量传入到过滤器中,然后过滤器根据自己的功 ...

  8. Springmvc多视图

    Springmvc多视图 多视图是一个方法可以返回json/xml等格式的数据 第一步:导入xml格式支持的jar包 spring-oxm-3.2.0.RC2.jar 第二步:配置支持多视图 < ...

  9. iOS动画效果合集、飞吧企鹅游戏、换肤方案、画板、文字效果等源码

    iOS精选源码 动画知识运用及常见动画效果收集 3D卡片拖拽卡片叠加卡片 iFIERO - FLYING PENGUIN 飞吧企鹅SpriteKit游戏(源码) Swift封装的空数据提醒界面Empt ...

  10. iOS路由详解

    本文如题,路由详解,注定是一篇详细解释iOS路由原理及使用的文章,由于此时正在外地出差,无法详细一一写出,只能不定时的补充. 一.什么是iOS路由 路由一词来源于路由器,可以实现层级之间消息转发的功能 ...