返回顶部
首页 > 资讯 > 后端开发 > Python >JVM之内存分配和回收机制
  • 348
分享到

JVM之内存分配和回收机制

JVM内存分配java内存回收 2023-05-18 14:05:51 348人浏览 八月长安

Python 官方文档:入门教程 => 点击学习

摘要

目录一、内存分配策略二、对象存活1.引用计数算法2.可达性分析算法3.再谈引用三、内存回收1.堆内存回收2.方法区回收总结前言 本篇主要介绍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虚拟机》。

--结束END--

本文标题: JVM之内存分配和回收机制

本文链接: https://www.lsjlt.com/news/212115.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • JVM之内存分配和回收机制
    目录一、内存分配策略二、对象存活1.引用计数算法2.可达性分析算法3.再谈引用三、内存回收1.堆内存回收2.方法区回收总结前言 本篇主要介绍JVM内存分配和回收策略,内容主要节选自《...
    99+
    2023-05-18
    JVM内存分配 java内存回收
  • 详解CLR的内存分配和回收机制
    一、CLR CLR:即公共语言运行时(Common Language Runtime),是中间语言(IL)的运行时环境,负责将编译生成的MSIL编译成计算机可以识别的机器码,负责资源...
    99+
    2024-04-02
  • Java内存分配与回收机制是什么
    本篇内容介绍了“Java内存分配与回收机制是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!一.运行时数据区域下图是Java虚拟机运行时的...
    99+
    2023-06-03
  • JVM分配和回收堆外内存的方式与注意点
    目录JVM内存模型如何分配堆外内存第一种方式:ByteBuffer#allocateDirect第二种方式:Unsafe#allocateMemory如何回收堆外内存第一种方式:Un...
    99+
    2024-04-02
  • JVM教程之内存管理和垃圾回收(三)
    JVM内存组成结构JVM栈由堆、栈、本地方法栈、方法区等部分组成,结构图如下所示:1)堆所有通过new创建的对象的内存都在堆中分配,其大小可以通过-Xmx和-Xms来控制。堆被划分为新生代和旧生代,新生代又被进一步划分为Eden和Survi...
    99+
    2023-05-31
    jvm 内存管理 垃圾回收
  • 【redis】内存回收机制
    https://blog.csdn.net/tr1912/article/details/81267910...
    99+
    2021-02-15
    【redis】内存回收机制
  • Android内存回收机制
    Android内存回收机制策略 1、GC 2、lowmemorykiller GC GC是java虚拟机的内存回收机制。Android GC原...
    99+
    2022-06-06
    Android
  • AS3 内存回收机制
           AS3相对于以前版本的功能增强了很多,在赋予它重任时,同时也要它付出代价:垃圾收集器不再支持自动为你收集垃圾。本文中,我为大家整理了一些资料。首先,我们先来了解下垃圾收集器是个什么东西?             (1)关于垃...
    99+
    2023-01-31
    机制 内存
  • 新手入门Jvm-- JVM对象创建与内存分配机制
    1. 对象的创建 对象创建的主要流程: 1.类加载检查 虚拟机遇到一条new指令时,首先将去检查这个指令的参数是否能在常量池中定位到一个类的符号引用,并且检查这个符号引用代表...
    99+
    2024-04-02
  • C++ 函数内存分配和销毁与垃圾回收机制的比较
    c++++ 使用函数内存分配和销毁,即显式管理内存分配和释放,而垃圾回收机制自动处理这些操作,避免内存泄漏但可能降低效率。 C++ 函数内存分配与销毁与垃圾回收机制的比较 简介 内存管...
    99+
    2024-04-22
    c++ 内存管理 python 垃圾回收器
  • Python的内存管理和垃圾回收机制
    本篇内容介绍了“Python的内存管理和垃圾回收机制”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!对象的内存使用赋值语句是语言最常见的功能了...
    99+
    2023-06-02
  • qt内存回收机制是什么
    Qt内存回收机制是通过自动垃圾回收(Garbage Collection,GC)和对象树(Object Tree)来实现的。在Qt中...
    99+
    2023-09-16
    qt
  • php内存回收机制是什么
    PHP的内存回收机制主要包括两个方面:引用计数和垃圾回收。1. 引用计数:PHP使用引用计数来跟踪内存中对象的引用数量。当一个对象被...
    99+
    2023-08-24
    php
  • JVM中垃圾回收机制的示例分析
    这篇文章主要介绍了JVM中垃圾回收机制的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。堆内存的划分分为三个部分(以下名词表示同一个区):新生区、新生代、年轻代养老区、...
    99+
    2023-06-29
  • Java内存分配与回收策略
    本篇内容介绍了“Java内存分配与回收策略”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!内存分配与回收策略Minor GC 和 Full G...
    99+
    2023-06-02
  • 深入了解java内存分配和回收策略
    一、导论java技术体系中所提到的内存自动化管理归根结底就是内存的分配与回收两个问题,之前已经和大家谈过java回收的相关知识,今天来和大家聊聊java对象的在内存中的分配。通俗的讲,对象的内存分配就是在堆上的分配,对象主要分配在新生代的E...
    99+
    2023-05-31
    java 内存分配 回收策略
  • php内存回收机制怎么掌握
    要掌握PHP内存回收机制,可以关注以下几个方面:1. 了解PHP的垃圾回收机制:PHP使用了基于引用计数的垃圾回收机制。当一个变量的...
    99+
    2023-09-06
    php
  • JavaScript面试必备之垃圾回收机制和内存泄漏详解
    目录1.垃圾回收机制1.1 标记清除1.2 引用计数2.什么是内存泄漏2.1 JavaScript内存分配和回收的关键词:GC根、作用域3.常见的几种内存泄漏的方式3.1 未被注意的...
    99+
    2023-05-19
    JavaScript垃圾回收机制 JavaScript垃圾回收 JavaScript内存泄露 JavaScript面试
  • Linux内存管理之内存回收的示例分析
    这篇文章主要介绍了Linux内存管理之内存回收的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。1.1 内存回收的目标不是所有的物理内存都可以参与回收的,比如要是把内核...
    99+
    2023-06-16
  • php内存管理机制与垃圾回收机制的示例分析
    这篇文章给大家分享的是有关php内存管理机制与垃圾回收机制的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。一、内存管理机制先看一段代码:<php//内存管理机制var_dump(memory_get...
    99+
    2023-06-15
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作