当前位置: 首页 > news >正文

Java内存管理 -JVM 垃圾回收

一.概述

相比起C和C++的自己回收内存,JAVA要方便得多,因为JVM会为我们自动分配内存以及回收内存。

在之前的JVM 之内存管理 中,我们介绍了JVM内存管理的几个区域,其中程序计数器以及虚拟机栈是线程私有的,随线程而灭,故而它是不用考虑垃圾回收的,因为线程结束其内存空间即释放。

而JAVA堆和方法区则不一样,JAVA堆和方法区时存放的是对象的实例信息以及对象的其他信息,这部分是垃圾回收的主要地点。

二.JAVA堆垃圾回收

垃圾回收主要考虑的问题有两个:一个是效率问题,一个是空间碎片问题。

而Java堆中的垃圾回收可以分为两个区域,一个是新生代,一个是老年代。其中新生代又分为一块比较大的Eden空间和两块较小的Survivor空间。因为新生代和老年代所存储的对象群体是不一样的,为了在效率和空间碎片问题中取得平衡,新生代和老年代所使用的垃圾回收算法是不一样。

新生代 -复制算法

从名字上就知道,新生代主要存放的是比较新的对象,回收多次之后仍然存活的对象,就会被送到老年代中区。由此可知新生代的垃圾回收是比较频繁的,所以为解决效率问题,新生代使用了复制算法。复制算法可以将内存分为大小相等的两块,每次分配时使用其中一块,当这一块用完时,就将还存活的对象复制到另一块内存上面区。此时已使用过的这一块内存就可以一次清理掉,这样也不用担心内存碎片的问题。当然这种算法的一个缺点就是内存使用率比较低,只有一半(每次只能一半用来分配出去)。

而IBM公司的研究表明,新生代中的对象98%都是”照生夕死“,所以不需要按照1:1划分,故而会将内存分为一块较大的Eden空间和两块小的Survivor空间。

那么为什么会有两块Survivor呢,复制算法不是只需要一块Eden和一块Survivor就够了吗?

其实这主要还是为了解决碎片化的问题。假设只有一个Survivor区,当Eden区满的时候,进行Gc,存活对象被分配到了Survivor区,清空Eden区。当再一次Gc完成后,存活的对象继续放在Survivor区,这样不是很美好吗,不会有内存碎片啊!但是别忘了,第一次存到Survivor区的对象很可能在第二次Gc的时候就失活了,清理掉Survivor失活对象不就会产生内存碎片了吗?

所以Java堆使用了两个Survivor区,一个from Survivro和一个toSurvivor,第一次Eden满的时候,复制算法将存活对象放到from Survivor区,清空Eden。第二次,Eden满时,将Eden和from Survivor区存活的对象放到to Survivor区,清空Eden和from Survivor,然后重要的一步,将from Survivor和to Survivor角色互换!这样就解决了内存碎片化的问题。
img_21579aefb6dd117e61535948a1f19854.png

老年代 -标记/整理算法

首先要明白老年代存放的都是会存活得比较久的对象,所以如果老年代也使用复制算法的话,那么复制对象的开销时比较大的,因为老年代的对象基本上都会存活。

标记/整理算法很好理解,主要也就是”标记“,”整理“两个步骤,先将要回收的对象标记,然后让存活对象向着一端移动,最后将边界以外的内存,然后Gc完成。
img_d05142f333d6cc9a631704e702f1ebf2.png

三.方法区垃圾回收

在某些地方的解释中,方法区也会被叫做“永久代”,与JAVA堆不同,这里存放的是类的信息以及一些常量信息,故而这个区域中被分配的内存一般比较难以被回收,所以才有有”永久代“之名。

虽然方法区中垃圾回收效率较低,但被分配的内存却也并非真的就永不被回收,其主要回收的有两部分内容:废弃常量和无用的类。废弃常量的回收与JAVA堆中类实例回收类似,当常量池中一个常量没有被引用时,就有可能被回收。比如常量池中有一个字符串常量“abc”,当没有任何一个String对象值为"abc"时,那么下一次垃圾回收"abc"常量就有可能会被回收。

而对于无用的类的回收,首先需要判断什么样的类才是”无用的类“:

  • 该类所有的实例都已被回收,即JAVA堆中没有该类的实例。
  • 加载类的ClassLoader已经被回收。
  • 该类对应的java.lang.Class对象没有在任何地方被引用,无法在任何地方通过反射访问该类的方法。

虚拟机可能会堆满足这三个条件的”无用的类“进行回收,仅仅是可能,并非必然。






相关文章:

  • POJ3259 SPFA判定负环
  • Qt5开发及实例学习
  • 深入BUG分析
  • HTML5的优缺点
  • 2018腾讯广告算法大赛总结/Rank7-复习代码
  • Android Studio NDK:三、打包SO
  • 7×14小时陪伴,DaDaBaby核心课程升级背后到底有多少考量?
  • java中hashset重写equals方法中只比较属性值的问题
  • WPF 标题栏 右键窗口标题添加关于对话框
  • 利用矩阵快速幂转换的题目
  • 最新软件工程师薪资大揭秘!你的薪资达到平均水平了吗?
  • Java自学之路(小白向)
  • 由两个栈组成队列
  • jenkins1
  • 为什么要用到Nginx来做负载均衡?通俗的解释
  • [译] React v16.8: 含有Hooks的版本
  • 《Javascript高级程序设计 (第三版)》第五章 引用类型
  • 【跃迁之路】【735天】程序员高效学习方法论探索系列(实验阶段492-2019.2.25)...
  • crontab执行失败的多种原因
  • JAVA_NIO系列——Channel和Buffer详解
  • javascript从右向左截取指定位数字符的3种方法
  • Rancher如何对接Ceph-RBD块存储
  • rc-form之最单纯情况
  • Tornado学习笔记(1)
  • 从0到1:PostCSS 插件开发最佳实践
  • 基于web的全景—— Pannellum小试
  • 理解IaaS, PaaS, SaaS等云模型 (Cloud Models)
  • 一个完整Java Web项目背后的密码
  • 用element的upload组件实现多图片上传和压缩
  • 用简单代码看卷积组块发展
  • 掌握面试——弹出框的实现(一道题中包含布局/js设计模式)
  • 哈罗单车融资几十亿元,蚂蚁金服与春华资本加持 ...
  • # C++之functional库用法整理
  • #{}和${}的区别?
  • #if 1...#endif
  • #我与Java虚拟机的故事#连载14:挑战高薪面试必看
  • (16)Reactor的测试——响应式Spring的道法术器
  • (2)STM32单片机上位机
  • (Matlab)基于蝙蝠算法实现电力系统经济调度
  • (牛客腾讯思维编程题)编码编码分组打印下标(java 版本+ C版本)
  • (十三)Java springcloud B2B2C o2o多用户商城 springcloud架构 - SSO单点登录之OAuth2.0 根据token获取用户信息(4)...
  • (转)一些感悟
  • .CSS-hover 的解释
  • .desktop 桌面快捷_Linux桌面环境那么多,这几款优秀的任你选
  • .Net 8.0 新的变化
  • .net core使用ef 6
  • .Net 代码性能 - (1)
  • .Net 知识杂记
  • .NET/C# 中设置当发生某个特定异常时进入断点(不借助 Visual Studio 的纯代码实现)
  • @Autowired多个相同类型bean装配问题
  • @param注解什么意思_9000字,通俗易懂的讲解下Java注解
  • @四年级家长,这条香港优才计划+华侨生联考捷径,一定要看!
  • [APUE]进程关系(下)
  • [AX]AX2012开发新特性-禁止表或者表字段
  • [C#]winform利用seetaface6实现C#人脸检测活体检测口罩检测年龄预测性别判断眼睛状态检测