Java 垃圾回收机制原理

2023-10-31

一:垃圾回收机制的意义

java  语言中一个显著的特点就是引入了java回收机制,是c++程序员最头疼的内存管理的问题迎刃而解,它使得java程序员在编写程序的时候不在考虑内存管理。由于有个垃圾回收机制,java中的额对象不在有“作用域”的概念,只有对象的引用才有“作用域”。垃圾回收可以有效的防止内存泄露,有效的使用空闲的内存;

说到这,不得不提起内存泄漏(memory leak)和内存溢出(out of memory)

内存泄漏:是指程序在申请内存后,无法释放已申请的内存空间,一次内存泄漏似乎不会有大的影响,但内存泄漏堆积后的后果就是内存溢出。

内存溢出:指程序申请内存时,没有足够的内存供申请者使用,或者说,给了你一块存储int类型数据的存储空间,但是你却存储long类型的数据,那么结果就是内存不够用,此时就会报错OOM,即所谓的内存溢出。 

通俗的说就是停车场(堆)保安(gc)让很久不用的废弃车子(无用的对象)从车位上挪走,但是这个车子又没办法挪走。这就是内存泄漏。停车场所有的车位都有车子占用了,再来车子没地了,或者说给你一个小汽车的停车位(int),你非要停一辆高铁(Long),这就是内存溢出。

内存泄露量大到一定程度会导致内存溢出。但是内存溢出不一定是内存泄露引起的。


内存泄漏的分类(按发生方式来分类)

常发性内存泄漏。发生内存泄漏的代码会被多次执行到,每次被执行的时候都会导致一块内存泄漏。
偶发性内存泄漏。发生内存泄漏的代码只有在某些特定环境或操作过程下才会发生。常发性和偶发性是相对的。对于特定的环境,偶发性的也许就变成了常发性的。所以测试环境和测试方法对检测内存泄漏至关重要。
一次性内存泄漏。发生内存泄漏的代码只会被执行一次,或者由于算法上的缺陷,导致总会有一块仅且一块内存发生泄漏。比如,在类的构造函数中分配内存,在析构函数中却没有释放该内存,所以内存泄漏只会发生一次。
隐式内存泄漏。程序在运行过程中不停的分配内存,但是直到结束的时候才释放内存。严格的说这里并没有发生内存泄漏,因为最终程序释放了所有申请的内存。但是对于一个服务器程序,需要运行几天,几周甚至几个月,不及时释放内存也可能导致最终耗尽系统的所有内存。所以,我们称这类内存泄漏为隐式内存泄漏


内存溢出原因: 
1.内存中加载的数据量过于庞大,如一次从数据库取出过多数据; 
2.集合类中有对对象的引用,使用完后未清空,使得JVM不能回收; 
3.代码中存在死循环或循环产生过多重复的对象实体; 
4.使用的第三方软件中的BUG; 
5.启动参数内存值设定的过小
内存溢出的解决方案: 

第一步,修改JVM启动参数,直接增加内存。(-Xms,-Xmx参数一定不要忘记加。)

第二步,检查错误日志,查看“OutOfMemory”错误前是否有其 它异常或错误。

第三步,对代码进行走查和分析,找出可能发生内存溢出的位置。

二:垃圾回收策略

分代的垃圾回收策略,是基于这样一个事实:不同的对象的生命周期是不一样的。因此,不同生命周期的对象可以采取不同的回收算法,以便提高回收效率。


年轻代(Young Generation)

1.所有新生成的对象首先都是放在年轻代的。年轻代的目标就是尽可能快速的收集掉那些生命周期短的对象。

2.新生代内存按照8:1:1的比例分为一个eden区和两个survivor(survivor0,survivor1)区。一个Eden区,两个 Survivor区(一般而言)。大部分对象在Eden区中生成。回收时先将eden区存活对象复制到一个survivor0区,然后清空eden区,当这个survivor0区也存放满了时,则将eden区和survivor0区存活对象复制到另一个survivor1区,然后清空eden和这个survivor0区,此时survivor0区是空的,然后将survivor0区和survivor1区交换,即保持survivor1区为空, 如此往复。

3.当survivor1区不足以存放 eden和survivor0的存活对象时,就将存活对象直接存放到老年代。若是老年代也满了就会触发一次Full GC,也就是新生代、老年代都进行回收

4.新生代发生的GC也叫做Minor GC,MinorGC发生频率比较高(不一定等Eden区满了才触发)

年老代(Old Generation)

1.在年轻代中经历了N次垃圾回收后仍然存活的对象,就会被放到年老代中。因此,可以认为年老代中存放的都是一些生命周期较长的对象。

2.内存比新生代也大很多(大概比例是1:2),当老年代内存满时触发Major GC即Full GC,Full GC发生频率比较低,老年代对象存活时间比较长,存活率标记高。

持久代(Permanent Generation)

用于存放静态文件,如Java类、方法等。持久代对垃圾回收没有显著影响,但是有些应用可能动态生成或者调用一些class,例如Hibernate 等,在这种时候需要设置一个比较大的持久代空间来存放这些运行过程中新增的类。

说到持久代,也称永久代,不得不说一句,在jdk新版本中,已经没有了永久代这个区域。


三.GC(垃圾收集器)

新生代收集器使用的收集器:Serial、PraNew、Parallel Scavenge

老年代收集器使用的收集器:Serial Old、Parallel Old、CMS

Serial收集器(复制算法)

新生代单线程收集器,标记和清理都是单线程,优点是简单高效。

Serial Old收集器(标记-整理算法)

老年代单线程收集器,Serial收集器的老年代版本。

ParNew收集器(停止-复制算法) 

新生代收集器,可以认为是Serial收集器的多线程版本,在多核CPU环境下有着比Serial更好的表现。

Parallel Scavenge收集器(停止-复制算法)

并行收集器,追求高吞吐量,高效利用CPU。吞吐量一般为99%, 吞吐量= 用户线程时间/(用户线程时间+GC线程时间)。适合后台应用等对交互相应要求不高的场景。

Parallel Old收集器(停止-复制算法)

Parallel Scavenge收集器的老年代版本,并行收集器,吞吐量优先

CMS(Concurrent Mark Sweep)收集器(标记-清理算法)

高并发、低停顿,追求最短GC回收停顿时间,cpu占用比较高,响应时间快,停顿时间短,多核cpu 追求高响应时间的选择

四:GC的执行机制
由于对象进行了分代处理,因此垃圾回收区域、时间也不一样。GC有两种类型:Scavenge GC和Full GC。

Scavenge GC

一般情况下,当新对象生成,并且在Eden申请空间失败时,就会触发Scavenge GC,对Eden区域进行GC,清除非存活对象,并且把尚且存活的对象移动到Survivor区。然后整理Survivor的两个区。这种方式的GC是对年轻代的Eden区进行,不会影响到年老代。因为大部分对象都是从Eden区开始的,同时Eden区不会分配的很大,所以Eden区的GC会频繁进行。因而,一般在这里需要使用速度快、效率高的算法,使Eden去能尽快空闲出来。

Full GC

对整个堆进行整理,包括Young、Tenured和Perm。Full GC因为需要对整个堆进行回收,所以比Scavenge GC要慢,因此应该尽可能减少Full GC的次数。在对JVM调优的过程中,很大一部分工作就是对于FullGC的调节。有如下原因可能导致Full GC:

1.年老代(Tenured)被写满

2.持久代(Perm)被写满

3.System.gc()被显示调用

4.上一次GC之后Heap的各域分配策略动态变化


--------------------- 
作者:野生在江南 
来源:CSDN 
原文:https://blog.csdn.net/wuzhixiu007/article/details/80116560 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Java 垃圾回收机制原理 的相关文章

  • 具有更高可见性的重写方法是良好的实践吗?

    回答这个问题 如何使用 GUI 使用 PaintComponent 初始化 GUI 然后添加基于鼠标的 GUI https stackoverflow com questions 21336141 how to gui using pain
  • 添加动态数量的监听器(Spring JMS)

    我需要添加多个侦听器 如中所述application properties文件 就像下面这样 InTopics Sample QUT4 Sample T05 Sample T01 Sample JT7 注意 这个数字可以多一些 也可以少一些
  • 对话框上的 EditText 不返回任何文本

    我太累了 找不到错误 我没有发现任何错误 但我没有从 editText 收到任何文本 请看下面的代码 活动密码 xml
  • Spring安全“记住我”cookie在第一个请求中不可用

    我无法在登录请求后检索 Spring 记住我 cookie 但它在对受保护页面的下一个请求中工作正常 谁能告诉我怎样才能立即得到它 我在登录请求中设置了记住我的 cookie 但在 Spring 重定向回原始 受保护的 url 后无法检索它
  • 如何在 JSP 中导入类?

    我是一个完全的JSP初学者 我正在尝试使用java util List在 JSP 页面中 我需要做什么才能使用除以下类之外的类java lang 使用以下导入语句进行导入java util List 顺便说一句 要导入多个类 请使用以下格式
  • 使用 RecyclerView 适配器在运行时更改布局屏幕

    我有两个布局文件 如下所示 如果列表中存在数据 则我显示此布局 当列表为空时 我会显示此布局 现在我想在运行时更改布局 当用户从列表中删除最后一项时 我想将布局更改为第二张图片中显示的 空购物车布局 In getItemCount Recy
  • 记录骆驼路线

    我的项目中有几个 Camel 上下文 如果可能的话 我想以逆向工程方式记录路线 因为我们希望保持与上下文相关的文档最新 最好的方法是什么 我们倾向于预先实际设计路线 并使用来自EIP book http www eaipatterns co
  • 如果使用的 JVM 是 x86 或 x64,则以不同的方式解决 Maven 依赖关系?

    我设置了一个 Maven 存储库来托管一些 dll 但我需要我的 Maven 项目根据使用的 JVM 是 x86 还是 x64 下载不同的 dll 例如 在运行 x86 版本 JVM 的计算机上 我需要从存储库下载 ABC dll 作为依赖
  • 内存一致性 - Java 中的happens-before关系[重复]

    这个问题在这里已经有答案了 在阅读有关内存一致性错误的 Java 文档时 我发现与创建 发生 之前 关系的两个操作相关的点 当语句调用时Thread start 每个具有 与该语句发生之前的关系也有一个 与 new 执行的每个语句之间发生的
  • 隐式超级构造函数 Person() 未定义。必须显式调用另一个构造函数?

    我正在开发一个项目 但收到错误 隐式超级构造函数 Person 未定义 必须显式调用另一个构造函数 我不太明白它 这是我的人物课程 public class Person public Person String name double D
  • 获取给定类文件的目录路径

    我遇到的代码尝试从类本身的 class 文件所在的同一目录中读取一些配置文件 File configFiles new File this getClass getResource getPath listFiles new Filenam
  • 如何记录来自 Akka (Java) 的所有传入消息

    在 Scala 中 您可以使用 LoggingReceive 包装接收函数 如何通过 Java API 实现相同的目标 def receive LoggingReceive case x do something Scala API 有Lo
  • Spring Security OAuth2简单配置

    我有一个简单的项目 需要以下简单的配置 我有一个 密码 grant type 这意味着我可以提交用户名 密码 用户在登录表单中输入 并在成功时获得 access token 有了该 access token 我就可以请求 API 并获取用户
  • Android Studio 将音乐文件读取为文本文件,如何恢复它?

    gameAlert mp3是我的声音文件 运行应用程序时 它询问我该文件不与任何文件类型关联 请定义关联 我选择TextFile错误地 现在我的音乐文件被读取为文本文件 我如何将其转换回music file protected void o
  • Espresso 和 Proguard 的 Java.lang.NoClassDefFoundError

    我对 Espresso 不太有经验 但我终于成功地运行了它 我有一个应用程序需要通过 Proguard 缩小才能处于 56K 方法之下 该应用程序以 3 秒的动画开始 因此我需要等到该动画结束才能继续 这就是我尝试用该方法做的事情waitF
  • 尝试使用等于“是”或“否”的字符串变量重新启动 do-while 循环

    计算行程距离的非常简单的程序 一周前刚刚开始 我有这个循环用于解决真或假问题 但我希望它适用于简单的 是 或 否 我为此分配的字符串是答案 public class Main public static void main String a
  • 将图像添加到自定义 AlertDialog

    我制作了一个 AlertDialog 让用户可以从我显示的 4 个选项中选择一个 前 3 个让他们在单击号码时直接拨打号码 第 4 个显示不同的视图 现在看起来是这样的 由于第四个选项的目的是不同的任务 我想让它看起来不同 因为用户可能会感
  • JVM:是否可以操作帧堆栈?

    假设我需要执行N同一线程中的任务 这些任务有时可能需要来自外部存储的一些值 我事先不知道哪个任务可能需要这样的值以及何时 获取速度要快得多M价值观是一次性的而不是相同的M值在M查询外部存储 注意我不能指望任务本身进行合作 它们只不过是 ja
  • 哪个集合更适合存储多维数组中的数据?

    我有一个multi dimensional array of string 我愿意将其转换为某种集合类型 以便我可以根据自己的意愿添加 删除和插入元素 在数组中 我无法删除特定位置的元素 我需要这样的集合 我可以在其中删除特定位置的数据 也
  • JSON 到 hashmap (杰克逊)

    我想将 JSON 转换为 HashMapJackson http jackson codehaus org 这是我的 JSON String json Opleidingen name Bijz trajecten zorg en welz

随机推荐

  • 使用Docker高效搭建开发环境(详细教程)

    在学习Docker镜像和容器之前 先给大家介绍下Docker的概念 在理解概念的基础上可以举一反三 1 Docker的核心为镜像和容器 有JAVA基础的小伙伴们可以理解为镜像就是JAVA中的类 容器为相关类的对象 一个镜像可以创建多个容器
  • ffmpeg快速将mkv转mp4

    想用pr来剪一些动漫视频 视频是mkv格式的 但是我的pr pro2021不支持mkv格式 只能先转成mp4格式再用pr剪切 ffmpeg的格式转换是最快的 官网下载ffmpeg https github com BtbN FFmpeg B
  • 【环境搭建】(二)在Ubuntu22.04安装/卸载软件Anaconda

    一个愿意伫立在巨人肩膀上的农民 1 Anaconda的主要功能 Anaconda是一个Python环境管理工具 因为不同的Python项目中可能需要同一个库的不同版本 为了避免冲突 Anaconda可以对不同Python项目创建自己的运行环
  • 生活笑话

    n多年前 传呼机还算比较稀罕的时候 有师兄A买了传呼机 师兄B说 要试一试看 好使不 遂打电话到呼台 小姐 请呼 站在那里不要动 等我们过去打你 小姐大惊 这种信息我们不能发 B师兄坚持 就得这么发 不一会儿 呼机响起 拿起一看 有人要打你
  • 详细讲述C++各种运算符重载

    详细讲述C 各种运算符重载 1 等号运算符重载 2 加号运算符重载 3 取地址运算符重载 4 前置 后置 运算符重载 4 1后置 的引用问题 4 2相关问题分析 5 重载类型强转运算符 6 括号运算符重载 7 输出运算符重载 8 星号运算符
  • jetbrains phpstorm插件开发环境搭建

    2018 04 14 重要更新 使用 gradle 进行构建可以免去下面大部分步骤 使用 gradle 我们仅需下载安装 JDK Idea 使用 gradle 的方法是 新建 Project 然后选择如下 使用 gradle 的好处是 不用
  • C++多态(虚函数)使用详解

    目录 1 什么是多态 1 1父类指针指向子类指针案例 2 多态 虚函数的基本使用 3 多态 虚函数表 3 1单个类的虚函数表 3 2使用继承的虚函数表 3 3多重继承的虚函数表 4 虚函数的修饰 4 1虚函数的修饰 final 4 2虚函数
  • windows 更改pip源

    在c user 或者用户 电脑的用户名 目录下创建一个命名为 pip 的文件夹 如 C Users Administrator pip 在该文件夹下创建一个命名为 pip ini 的文件 在该文件中写入以下内容 global index u
  • SpringBoot之定时任务详解

    使用SpringBoot创建定时任务 目前主要有以下三种创建方式 一 基于注解 Scheduled 二 基于接口 SchedulingConfigurer 前者相信大家都很熟悉 但是实际使用中我们往往想从数据库中读取指定时间来动态执行定时任
  • 客观面试题--37.Spring/SpringMVC常用注解有哪些?

    Spring常用注解 使用注解来构造IoC容器 用注解来向Spring容器注册Bean 需要在applicationContext xml中注册
  • Microsoft Exchange ProxyShell Remote Code Execution CVE-2021-34473 (Metasploit exploits)分析

    CVE 2021 34473 加载winrm模块文件 Windows专用链接对象 https github com WinRb WinRM require winrm class MetasploitModule lt Msf Exploi
  • gdb调试,splint_valgrind代码检查

    文章目录 基本调试命令 语法 为什么没有产生core 文件 一 GDB 1 test 2 常用命令 3 使用core 二 代码检查 1 splint 2 valgrind 常见错误 命令格式 test1 test2 编译一个多种内存使用错误
  • Minor GC 过程

    如果Eden空间占满了 会触发 minor GC Minor GC后仍然存活的对象会被复制到S0中去 这样Eden就被清空可以分配给新的对象 又触发了一次 Minor GC S0和Eden中存活的对象被复制到S1中 并且S0和Eden被清空
  • TypeScript 最快速的入门教程

    TypeScript 最快速的入门教程 在线阅读 https niexia github io typescript tutorial 英文原版 https www typescripttutorial net 如果对你有帮助 欢迎在 gi
  • HarmonyOS开发详解(二)——鸿蒙开发体系详解及入门实例演示运行

    本篇文章的计划 先体系的介绍一下鸿蒙开发相关的体系内容 希望通过本篇内容构建对鸿蒙开发体系的了解 最后再来一个最简单入门例子 既是自我的学习 也希望对你了解鸿蒙开发的全貌有帮助 这样安排而没有直接写一个Helloworld例子的原因 很多朋
  • Leetcode 剑指Offer

    求 1 2 n 要求不能使用乘除法 for while if else switch case等关键字及条件判断语句 A B C 示例 1 输入 n 3 输出 6 示例 2 输入 n 9 输出 45 一 信息 1 求一个等差数列的求和 2
  • React教程(一)React基础

    1 React基础 目标 能够说出React是什么 能够说出React特点 能够掌握React的基本使用 能够使用React脚手架 1 1 React概述 官方网址 https zh hans reactjs org 1 1 1 什么是Re
  • jacob 导出word文档打开显示为web视图问题

    问题产生 由于是使用html 另存为word导致打开生成的word文档为web视图 Dispatch call this document SaveAs outputPath 问题解决 1 创建空的word 文档 this document
  • (大全)预后Cox 列线图Nomogram 校正曲线calibration curve 时间依赖ROC survivalROC C指数C-index 两ROC比较

    Cox模型 等比例风险检验 Nomogram C index 校准曲线 时间 ROC曲线 内置包数据运行 预期结果看图 部分代码加上自己的理解 可以直接复制到R运行 加载包 我用 R 3 6版本的 library cmprsk 已经包含在这
  • Java 垃圾回收机制原理

    一 垃圾回收机制的意义 java 语言中一个显著的特点就是引入了java回收机制 是c 程序员最头疼的内存管理的问题迎刃而解 它使得java程序员在编写程序的时候不在考虑内存管理 由于有个垃圾回收机制 java中的额对象不在有 作用域 的概