我的编程空间,编程开发者的网络收藏夹
学习永远不晚

JVM之内存分配和回收机制

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

JVM之内存分配和回收机制

前言

本篇主要介绍JVM内存分配和回收策略,内容主要节选自《深入理解java虚拟机》。

一、内存分配策略

1. 堆内存模型

在这里插入图片描述

组成:

  • 新生代 默认占堆空间的三分之一,由于在新生代对象大多都是朝生夕死,则采用的是复制算法,在复制的期间会有频繁的Minor GC。
  • 老年代 默认占堆空间的三分之二,老年代对象大多都是长期存活的,则采用的是标记算法,老年代的Major GC开销非常大。
  • Eden 新生代分为2个区 Eden和Survivor区 其中Eden区默认占新生代十分之八的空间,对象优先进入Eden区。
  • Survivor 当Eden区内存满了之后会进行一次Minor GC存活对象会进入Survivor区,默认占新生代十分之二空间, 其中它又均分为From区和To区,在Survivor区的对象每熬过一次从From区到TO区则年龄+1。

大多情况下,对象在新生代Eden区中分配。当Eden没有足够的空间分配对象时虚拟机会发起一次Minor GC。

2.2 大对象直接到老年代

大对象即需要大量连续内存空间的对象(例如很长的字符串及数组)。虚拟机提供了一个-XX:PretenureSizeThreshoId参数,令大于这个设置值的对象直接在老年代分配,这样做的目的是避免在Eden区及两个区之间发生大量的内存复制。注意PretenureSizeThreshoId参数只对Serial和ParNew两款收集器有效。

2.3 动态年龄判断

为了能更好地适应不同程序的内存状况,虚拟机并不是永远地要求对象的年龄必须达到了MaxTenuringThreshold才能晋升老年代,如果在Survivor空间中相同年龄所有对象大小的总和大于Survivor空间的一半,年龄大于或等于该年龄的对象就可以直接进人老年代,无须等到MaxTenuringThreshoId中要求的年龄。

2.4 内存担保机制

在发生Minor GC之前,虚拟机会先检查Survivor空间是否够用,如果够用则直接进行Minor GC。否则进行检查老年代最大连续可用空间是否大于新生代的总和,假如大于,那么这个时候发生Minor GC是安全的。假如不大于,那么需要判断HandlePromotionFailure设置是否允许担保失败。假如允许,则继续判定老年代最大可用的连续空间是否大于平均晋升到老年代对象的平均值,如果大于,这个时候可以发生Minor GC ,如果小于或者设置HandlePromotionFailure不允许担保失败,则需要做一次Full GC。通常会把HandlePromotionFailure开关打开,以减少Full GC。

2.5 长期存活对象

虚拟机给每个对象定义了一个对象年龄(Age)计数器(存在于对象头中)。如果对象在Eden出生并经过第一次MinorGC后仍然存活,并且能被Survivor容纳的话,将被移动到Survwor空间中,并且对象年龄设为1。对象在Survivor区中每“熬过”一次MinorGC,年龄就增加1岁,当它的年龄增加到一定程度(默认为15岁),就将会被晋升到老年代中。对象晋升老年代的年龄阈值,可以通过参数-XX:MaxTenuringThreshoId设置。

二、对象存活

判断对象存活一般有两种方式: 引用计数算法和可达性分析算法。

1.引用计数算法

原理:

  1. 引用计数算法(Reference Counting)比较简单,对每个对象保存一个整型的引用计数器属性。用于记录对象被引用的情况。
  2. 对于一个对象A,只要有任何一个对象引用了A,则A的引用计数器就加1;当引用失效时,引用计数器就减1。只要对象A的引用计数器的值为0,即表示对象A不可能再被使用,可进行回收。

优点:

  1. 实现简单,垃圾对象便于辨识;
  2. 判定效率高,回收没有延迟性。

缺点:

  1. 它需要单独的字段存储计数器,这样的做法增加了存储空间的开销。
  2. 每次复制都需要更新计数器,伴随着加法和减法操作,这增加了时间开销。
  3. 引用计数器有一个严重的问题,即无法处理循环引用的情况。这是一条致命缺陷,导致在Java的垃圾回收器中没有使用这类算法。

2.可达性分析算法

定义:相对于引用计数算法而言,可达性分析算法不仅同样具备实现简单和执行高效等特点,更重要的是该算法可以有效地解决在引用计数算法中循环引用的问题,防止内存泄漏的发生。

原理:

  1. 可达性分析算法是以根对象集合(GCRoots)为起始点,按照从上至下的方式搜索被根对象集合所连接的目标对象是否可达。
  2. 使用可达性分析算法后,内存中的存活对象都会被根对象集合直接或间接连接着,搜索所走过的路径称为引用链(Reference Chain)。
  3. 如果目标对象没有任何引用链相连,则是不可达的,就意味着该对象己经死亡,可以标记为垃圾对象。
  4. 在可达性分析算法中,只有能够被根对象集合直接或者间接连接的对象才是存活对象。


在这里插入图片描述

GC ROOT 对象:

  • 虚拟机栈中引用的对象;
    比如:各个线程被调用的方法中使用到的参数、局部变量等。
  • 本地方法栈内 JNI(通常说的本地方法)引用的对象;
  • 方法区中类静态属性引用的对象;
    比如:Java类的引用类型静态变量
  • 方法区中常量引用的对象;
    比如:字符串常量池(string Table)里的引用
  • 所有被同步锁 synchronized 持有的对象;
  • Java虚拟机内部的引用。
    基本数据类型对应的 Class 对象,一些常驻的异常对象(如:NullPointerException、OutOfMemoryError),系统类加载器。

3.再谈引用

  • 强引用:强引用在代码中普遍存在,例如Object obj=new Object() 这类的引用。只要强引用存在,垃圾回收器永远不会回收掉被引用的对象。
  • 软引用:软引用来描述一些还有用但并非必须的对象,在系统要发生内存溢出之前,将会把这些对象列入回收范围之中进行第二次回收,如果第二次回收还没有足够的内存,才会抛出内存溢出异常。
  • 弱引用:弱引用也是用来描述必须对象的,但是它的强度比软引用更弱,被弱引用关联的对象只能生存到下一次垃圾回收发生之前。当垃圾回收器工作时,无论内存是否足够,都回收掉只被弱引用关联的对象。
  • 虚引用:它是最弱的一种引用关系。它无法通过虚引用来取得一个对象实例。唯一目的就是能在这个对象被回收之前会收到一个系统通知。

三、内存回收

1.堆内存回收

是JVM所管理内存最大的一块,也是gc回收的主要区域。

1.1 哪些对象能回收?

堆内存中对象存活是使用可达性分析算法来判断,其中非存活对象由GC回收掉。这个就是虚拟机需要回收堆的对象。

1.2 如何回收?

  1. Minor GC:新生代收集,目标只是新生代的垃圾收集;
  2. Major GC:老年代收集,目标是老年代的垃圾收集(具体说只有CMS会有单独收集老年代的行为);
  3. Full GC:收集整个java堆和方法区的垃圾收集。这里补充说明一下虽然网上很多说什么Full GC就是Major GC,在这里我要重申一下并不是,具体看书上描述如下:


在这里插入图片描述

Mixed GC:收集整个新生代以及部分老年代的垃圾收集,仅G1支持。(类似于Full GC)

1.3 什么时候回收?

Minor GC触发条件:

  1. Eden区域满了,会触发Minor GC;
  2. 新生对象需要分配到新生代的Eden,当Eden区的内存不够时需要进行MinorGC。

Major GC触发条件:

  1. 老年代区域设置的阈值空间满了,会触发Major GC;
  2. 新对象需要分配到老年代,此时老年代设置阈值可用空间不足时触发Major GC。

Full GC触发条件:

  • 内存担保机制 ,Survivor空间不足时,判断是否允许担保失败,如果不允许则进行Full GC。如果允许,并且每次晋升到老年代的对象平均大小>老年代最大可用连续内存空间,也会进行Full GC;
  • MinorGC后存活的对象超过了老年代剩余空间;
  • 方法区内存不足时;
  • 程序中调用了System.gc()方法,可用通过-XX:+ DisableExplicitGC来禁止调用System.gc;
  • CMS GC异常,CMS运行期间预留的内存无法满足程序需要,就会出现一次“Concurrent Mode Failure”失败,会触发Full GC。

2.方法区回收

方法区主要回收废弃的常量池和不再使用类型,但这个2类对象存活的判断还不一样。

2.1 常量池

同堆的对象存活类似-可达性分析法,具体请参考之前的可达性分析法。

2.2 类型数据

  • 该类索引的实例都已经被回收;
  • 加载该类的类加载器已经被回收;
  • 该类对应的java.lang.class对象没有任何地方被引用。

以上都是我简单总结,以下是书上关于方法区回收描述的内容:


在这里插入图片描述

其实从书上就可以看出来,关于方法区OOM问题大都是在程序中是有大量使用反射、动态代理、CGLIB等框架,如果在实际开发中遇到关于可以从以上几个维度来定位问题。

总结

本篇所有理论知识都是摘抄于《深入理解java虚拟机》,有部分是自己简单总结,JVM内存分配和回收是我们在分析JVM调优和相关问题的基石,建议看完我本篇的去多看几遍《深入理解java虚拟机》。

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

JVM之内存分配和回收机制

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

JVM之内存分配和回收机制

本篇主要介绍JVM内存分配和回收策略,内容主要节选自《深入理解java虚拟机》,需要的朋友可以参考下
2023-05-18

Java内存分配与回收机制是什么

本篇内容介绍了“Java内存分配与回收机制是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!一.运行时数据区域下图是Java虚拟机运行时的
2023-06-03

JVM教程之内存管理和垃圾回收(三)

JVM内存组成结构JVM栈由堆、栈、本地方法栈、方法区等部分组成,结构图如下所示:1)堆所有通过new创建的对象的内存都在堆中分配,其大小可以通过-Xmx和-Xms来控制。堆被划分为新生代和旧生代,新生代又被进一步划分为Eden和Survi
2023-05-31

Android内存回收机制

Android内存回收机制策略 1、GC 2、lowmemorykillerGC GC是java虚拟机的内存回收机制。Android GC原理探究https://www.jianshu.com/p/a7f31aee4e2e lowmemor
2022-06-06

【redis】内存回收机制

https://blog.csdn.net/tr1912/article/details/81267910
【redis】内存回收机制
2021-02-15

AS3 内存回收机制

AS3相对于以前版本的功能增强了很多,在赋予它重任时,同时也要它付出代价:垃圾收集器不再支持自动为你收集垃圾。本文中,我为大家整理了一些资料。首先,我们先来了解下垃圾收集器是个什么东西?             (1)关于垃圾收集器    
2023-01-31

C++ 函数内存分配和销毁与垃圾回收机制的比较

c++++ 使用函数内存分配和销毁,即显式管理内存分配和释放,而垃圾回收机制自动处理这些操作,避免内存泄漏但可能降低效率。C++ 函数内存分配与销毁与垃圾回收机制的比较简介内存管理是编程中的一个关键方面。C++ 使用函数内存分配和销毁机
C++ 函数内存分配和销毁与垃圾回收机制的比较
2024-04-22

Python的内存管理和垃圾回收机制

本篇内容介绍了“Python的内存管理和垃圾回收机制”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!对象的内存使用赋值语句是语言最常见的功能了
2023-06-02

JVM中垃圾回收机制的示例分析

这篇文章主要介绍了JVM中垃圾回收机制的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。堆内存的划分分为三个部分(以下名词表示同一个区):新生区、新生代、年轻代养老区、
2023-06-29

php内存回收机制是什么

PHP的内存回收机制主要包括两个方面:引用计数和垃圾回收。1. 引用计数:PHP使用引用计数来跟踪内存中对象的引用数量。当一个对象被引用时,它的引用计数加1;当一个对象的引用被释放时,它的引用计数减1。当一个对象的引用计数为0时,表示该对象
2023-08-24

qt内存回收机制是什么

Qt内存回收机制是通过自动垃圾回收(Garbage Collection,GC)和对象树(Object Tree)来实现的。在Qt中,使用了一种基于引用计数的自动垃圾回收机制。每个QObject对象都维护着一个引用计数,当对象被创建时,引用
2023-09-16

Java内存分配与回收策略

本篇内容介绍了“Java内存分配与回收策略”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!内存分配与回收策略Minor GC 和 Full G
2023-06-02

Java中的JVM是如何实现内存管理的?(请解释Java虚拟机(JVM)如何进行内存分配与回收?)

Java虚拟机(JVM)通过自动内存管理机制,在Java程序运行时管理内存分配和回收。新创建的对象分配到堆内存的年轻代,称为伊甸园,存活时间增长后晋升到幸存者区域,再晋升到年老代。JVM使用不同的垃圾回收器,如标记-清除、复制和标记-整理,清除垃圾对象。此外,JVM还提供其他内存管理机制,如本地内存、栈内存和方法区,确保程序稳定运行。
Java中的JVM是如何实现内存管理的?(请解释Java虚拟机(JVM)如何进行内存分配与回收?)
2024-04-02

深入了解java内存分配和回收策略

一、导论java技术体系中所提到的内存自动化管理归根结底就是内存的分配与回收两个问题,之前已经和大家谈过java回收的相关知识,今天来和大家聊聊java对象的在内存中的分配。通俗的讲,对象的内存分配就是在堆上的分配,对象主要分配在新生代的E
2023-05-31

php内存回收机制怎么掌握

要掌握PHP内存回收机制,可以关注以下几个方面:1. 了解PHP的垃圾回收机制:PHP使用了基于引用计数的垃圾回收机制。当一个变量的引用计数为0时,说明该变量不再被使用,可以被回收。PHP通过在变量赋值、函数调用、函数返回等场景来更新引用计
2023-09-06

JavaScript面试必备之垃圾回收机制和内存泄漏详解

垃圾回收机制和内存泄漏是JavaScript面试时常常问到的问题,这篇文章就为大家详细整理了他们的相关知识,感兴趣的小伙伴可以跟随小编一起了解一下
2023-05-19

Linux内存管理之内存回收的示例分析

这篇文章主要介绍了Linux内存管理之内存回收的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。1.1 内存回收的目标不是所有的物理内存都可以参与回收的,比如要是把内核
2023-06-16

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录