前言

为什么需要垃圾回收

  • 首先我们来聊聊为什么会需要垃圾回收,假设我们不进行垃圾回收会造成什么后果,我们举一个简单的例子
  • 我们住在一个房子里面,我们每天都在里面生活,然后垃圾都丢在房子里面,又不打扫,最后房子都是垃圾 我们是不是就没法住下去了。
  • 所以JVM垃圾回收机制也是一样的,当我们创建的对象占据堆空间要满了的的时候我们就对他进行垃圾回收,注意java的垃圾回收是不定时的,c语言的是需要去调用垃圾回收方法
  • 刚刚也说到 上面举的例子也说到 假设一个房子都被垃圾堆满了 那么我们没法住人了 那么我们是不是会告诉别人这个房子没法住人了 而java也是如此当我们堆空间满了的时候 此时它就会抛出异常OutOfMemoryError(简称OOM)

什么地方需要进行垃圾回收

刚刚我们说了为什么要回收垃圾,和什么是OOM那么我们下面就给大家介绍,我们JVM中什么地方需要进行垃圾回收。

垃圾回收要考虑的点

1)是否会产生垃圾

2)哪些内存需要回收

3)什么时候回收

4)如何对他进行回收


程序计数器

jvm中唯一 一个不需要垃圾回收的地方。

栈 本地方法栈

这个地方会因为栈帧存满了导致内存溢出,所以需要垃圾回收

方法区(元空间)

这个地方也需要进行垃圾回收



这个地方是我们垃圾回收最频繁的地方,我们几乎我们所有的对象都存储在堆中,也是我们今天要着重讲的地方

堆GC

堆,可能大家都不陌生,可是好像又距离我们很远,今天它来了

从上面的图我们可以看出 ,我们的堆空间被主要被划分为了二块区域 ,新生代 ,老年代 java堆是我们JVM中管理区域最大的一块, java堆是一个线程共享的区域 ,在虚拟机启动时创建 ,几乎所有的对象都在此分配, java虚拟机规范中有过描述,所有的实例对象以及数组都在堆中进行分配内存, 但目前因为JTI编译器的发展,和逃逸分析技术的逐渐完善,在堆中分配对象也不是那么的绝对了。

堆的内存在物理上可以是不连续的,但是在逻辑上是即可。

新生代

  • 我们对象的创建到结束,几乎是"朝生夕死"的一个过程差不多90%的对象都在新生代被回收了,所以新生代的gc也是发生最为频繁的一个区域。新生代产生gc我们称为Y-GC
  • 每产生一次y-gc我们对象的年龄就加一岁,直到15岁后进入老年代。当然这是正常情况,那么有没有特殊情况勒当然有

空间担保

  • 当我们创建的对象大于Eden的时候,此时怎么办,此时他会先产生一次Y-GC如果还是无法存储下新创建的对象,那么我们就会通过空间担保策略进入老年代。
  • 还有一种情况,对象创建也会直接进入老年代,当我们的Surivivor区满了的时候,此时它不会主动产生gc只会依赖于Eden,但我们的对象又不能被抛弃,所以它也被分配到了老年代
  • 当然我们实际开发工作中需要尽量的去避免这种情况的诞生

动态年龄

  • 什么是动态年龄勒,这是堆中的另一个,担保策略了,它会去判断我们Surivivor的区中,相同年龄的对象大于Surivivor区一半的时候,那么他就会判定此时这些对象已经能够很好的存活了,所以他们就集体被丢到老年代了

对象如何分配内存

老年代

  • 我们老年代存放的都是一些老对象了,大对象,都是存活时间较长的对象这里一般很少产生FGC这里一旦产生FGC那么所产生GC的耗时将会是YGC的10倍时耗,而我们老年代快要存满时进入了一个对象,这时会产生一次FGC如果GC结束后,还是无法存放对象的话此时就会报OOM异常。

垃圾回收算法

分代算法

分代算法,其实也就是将我们堆空间划分为了一个个不同的区域,新生代,老年代,不让它回收的时候对整个堆进行一个回收。减少GC所停顿的时间,我们称之为STW (Stop The World),假设我们堆整个堆进行垃圾回收,是不是每次都需要去把整个堆的垃圾标记一次,非常的那么用户线程停止的时间就非常长,你想一下,假如你的电脑每使用1个小时就卡10秒,那么你是不是非常操蛋。

标记清除

算法执行过程

堆空间垃圾清理前

垃圾清除后

算法介绍

标记清除是最开始jvm选择的一种垃圾回收算法,这个算法就和他的名字一样,分为标记,和清除二个过程,首先他会标记所有需要回收的对象,标记结束后对标记的对象进行一个垃圾回收。

缺点

这种方式会有什么缺点呢!它会导致内存空间的浪费,产生大佬不连续的内存碎片,当我们需要一个连续的内存空间存放大对象的时候,因为连续的内存空间不够,导致我们不得又产生一次GC,提高了我们GC产生的频率。

标记整理

算法执行过程

算法介绍

标记整理,的执行过程,于标记清除相反,标记清除是标记需要回收的对象,而标记整理却是标记存活的对象,然后把他们全部向一段进行位移,然后清除端边界以外的所有对象。

适用范围

老年代垃圾回收

复制算法

算法执行过程

算法介绍

复制算法也是在标记清除上的一个改进,它弥补了标记清除出现大量不连续内存碎片的缺点。它将一个可用的内存空间划分为大小相等的二块区域,每次只使用其中一块区域,当这块区域用完了就把存活的对象放到,另一块空着的区域区,然后把自己清除干净,变成一块空着的区域。这样就解决了内存碎片的问题

缺点

那么这样的算法是不是太过于苛刻了,每次都需要一块空着的区域用于存放对象,牺牲掉了大量的内存。

适用范围

新生代Surivivor区域

堆中对象内存的分配策略

指针碰撞

这种分配方式其实是复制算法,标记整理中的携带的一种对象分配策略,我们如何区分什么是用过的,什么是没用过的,这时我们通过一个指针,作为一个分界点指示器,那所需要分配的内存,就仅仅是把指示器指针向空闲空间那边挪动一段与对象大小相等的距离,这种分配方式称为"指针碰撞"(Bump the Pointer)。

空闲列表

空闲是标记清除中对对象分配的一个策略,因为标记清除中我们的内存划分的随机的,已使用内存和未使用内存相互交错,那么我们如何把他们关联起来,虚拟机针对这种交错的内存维护了一个列表,记录哪些内存块是可用的,在分配的时候找到一块足够大的空间划分给对象实例,并更新列表上的记录,这种分配方式成为"空闲列表"(Free List)。

OOM异常

其实OOM在上面介绍了堆内存的划分和收集过程中,大家也应该对它有了一定的认识了,OOM异常是发生在老年代Old中的一个异常,当我们老年代中无法在存放对象的时候,就会报OOM内存溢出异常

public class HeapOomError {
public static void main(String[] args) {
List<byte[]> list =new ArrayList<>();
int i=0;
while (true){
try {
Thread.sleep(100);
} catch (InterruptedException e){
e.printStackTrace();
}
list.add(new byte[5 * 1024 * 1024]);
//System.out.println("count is:"+(++i));
}
}
}

设置堆空间的大小

最后我们得到的结果如下

总结

总而言之我们需要的优化的GC的损耗和避免内存溢出的出现,从而提高我用户良好使用体验。

最后

感谢你看到这里,看完有什么的不懂的可以在评论区问我,觉得文章对你有帮助的话记得给我点个赞,每天都会分享java相关技术文章或行业资讯,欢迎大家关注和转发文章!

真的可惜,四面阿里,结果我被JVM垃圾回收机制与 OOM异常卡住了的更多相关文章

  1. JVM垃圾回收机制总结:调优方法

    转载: JVM垃圾回收机制总结:调优方法 JVM 优化经验总结 JVM 垃圾回收器工作原理及使用实例介绍

  2. JVM内存管理和JVM垃圾回收机制

    JVM内存管理和JVM垃圾回收机制(1) 这里向大家描述一下JVM学习笔记之JVM内存管理和JVM垃圾回收的概念,JVM内存结构由堆.栈.本地方法栈.方法区等部分组成,另外JVM分别对新生代和旧生代采 ...

  3. JVM垃圾回收机制概述

    JVM垃圾回收机制概述 1.定义 是指JVM用于释放那些不再使用的对象所占用的内存. 2.方式 2.1引用计数(早期) 当引用程序创建引用以及引用超出范围时,JVM必须适当增减引用数.当某个对象的引用 ...

  4. Java虚拟机学习笔记——JVM垃圾回收机制

    Java虚拟机学习笔记——JVM垃圾回收机制 Java垃圾回收基于虚拟机的自动内存管理机制,我们不需要为每一个对象进行释放内存,不容易发生内存泄漏和内存溢出问题. 但是自动内存管理机制不是万能药,我们 ...

  5. JVM基础系列第8讲:JVM 垃圾回收机制

    在第 6 讲中我们说到 Java 虚拟机的内存结构,提到了这部分的规范其实是由<Java 虚拟机规范>指定的,每个 Java 虚拟机可能都有不同的实现.其实涉及到 Java 虚拟机的内存, ...

  6. JVM内存管理、JVM垃圾回收机制、新生代、老年代以及永久代

    内存模型 JVM运行时数据区由程序计数器.堆.虚拟机栈.本地方法栈.方法区部分组成,结构图如下所示. JVM内存结构由程序计数器.堆.栈.本地方法栈.方法区等部分组成,结构图如下所示: 1)程序计数器 ...

  7. JVM 垃圾回收机制和常见算法和 JVM 的内存结构和内存分配(面试题)

    一.JVM 垃圾回收机制和常见算法 Sun 公司只定义了垃圾回收机制规则而不局限于其实现算法,因此不同厂商生产的虚拟机采用的算法也不尽相同.GC(Garbage Collector)在回收对象前首先必 ...

  8. JVM垃圾回收机制和常用算法

    由于疫情的原因,所以目前一直在家远程办公,所以很多时间在刷面试题,发现2019大厂的面试虽然种类很多,但是总结了一下发现主要是这几点:算法和数据结构. JVM.集合.多线程.数据库这几点在面试的时候比 ...

  9. java JVM垃圾回收机制

    Java语言出来之前,大家都在拼命的写C或者C++的程序,而此时存在一个很大的矛盾,C++等语言创建对象要不断的去开辟空间,不用的时候有需要不断的去释放控件,既要写构造函数,又要写析构函数,很多时候都 ...

随机推荐

  1. Window Mysql 解压安装

    下载MySQL zip文件 解压后没有data文件夹和my.ini文件, 在根目录下创建my.ini文件,输入如下内容 以管理员身份运行cmd ,进入bin目录 ,运行下列命令,即可. a) mysq ...

  2. AQS 自定义同步锁,挺难的!

    AQS是AbstractQueuedSynchronizer的简称. AbstractQueuedSynchronizer 同步状态 AbstractQueuedSynchronizer 内部有一个s ...

  3. 【踩坑系列】使用long类型处理金额,科学计数法导致金额转大写异常

    1. 踩坑经历 上周,一个用户反馈他创建的某个销售单无法打开,但其余销售单都可以正常打开,当时查看了生产环境的ERROR日志,发现抛了这样的异常:java.lang.NumberFormatExcep ...

  4. Python&&Pip

    Pip简易使用 使用pip list命令就可以发现自己电脑里所安装库的名字.如图展示的出来的有package.Version.Location三列,package是下载的python库名,Versio ...

  5. D. Number of Parallelograms 解析(幾何)

    Codeforce 660 D. Number of Parallelograms 解析(幾何) 今天我們來看看CF660D 題目連結 題目 給你一些點,求有多少個平行四邊形. 前言 @copyrig ...

  6. Express 配置HTML页面访问

    Express 配置HTML页面访问 1.配置模板引擎 Express默认的模板引擎是pug(jade),想要渲染html页面必须要导入对应的模板引擎ejs npm install ejs 安装完成在 ...

  7. SQL Server 列存储索引 第四篇:实时运营数据分析

    实时运营数据分析(real-time operational analytics )是指同时在同一张数据表上执行分析处理和业务处理.分析查询主要是对海量数据执行聚合查询,而事务主要是指对数据表进行少量 ...

  8. cookie与session的概念与区别

    会话(Session)跟踪是Web程序中常用的技术,用来跟踪用户的整个会话.常用的会话跟踪技术是Cookie与Session.Cookie通过在客户端记录信息确定用户身份,Session通过在服务器端 ...

  9. [C#.NET 拾遗补漏]11:最基础的线程知识

    线程的知识太多,知识点有深有浅,往深的研究会涉及操作系统.CUP.内存,往浅了说就是一些语法.没有一定的知识积累,很难把线程的知识写得全面,当然我也没有这个能力.所以想到一个点写一个点,尽量总结一些有 ...

  10. 【SpringBoot】09.SpringBoot整合Freemarker

    SpringBoot整合Freemarker 1.修改pom文件,添加坐标freemarker启动器坐标 <project xmlns="http://maven.apache.org ...