为何要“除夕”,原来是内存爆了!

传说古代有一只四角四足的怪兽:名叫。因冬天大雪致使夕没东西吃,因此夕常常到附近的村里找吃的,因其身体庞大、脾气暴躁、凶猛异常,给村民带来了很大的灾难。java

后来有一位聪明的孩子,他叫作,教给你们除掉“夕”的方法:用爆竹,轻则赶走它,重则伤它。每一年腊月三十,夕都会来村里,村名就守着夜,放着鞭炮赶走夕。除夕由此而来。程序员

咱们把“夕”想象成一个不断吃机器内存的 Jav a 程序,就称它为 年兽 吧。 掌管 Java 虚拟机内存的就是“年”,咱们称它为 年哥 吧。

年兽的地盘

年哥管理的地盘主要分为五大区:堆、方法区、虚拟机栈、本地方法栈、程序计数器。以下图所示。另外你们能够把图中的线程想象成村民,而是做为村民共享使用的区域。算法

运行时数据区小程序

堆又能够进行细分,分为新生代老年代,新生代和老年代的比例是 1:2,而新生代又能够进行细分,分为伊甸园(Eden)区和两个 Survivor, 其中 Eden 区大小和 Survivor 区大小是 8:1。数组

以下图所示,年兽和村民都是共享堆内存这块地盘的,管理员年哥是管理堆内存的。其中的数字 一、八、20 分别表明占用内存的份数。微信

共享堆区架构

年兽的胃口

年兽的胃口是村民的几百倍,年兽假扮村民逃过了管理员年哥的检查,年哥对于这种大胃王都是直接分配到老年代去的,由于大胃王须要连续的内存给它吃,而新生代的碎片比较多不知足条件。在 Java 的世界中,最典型的大胃王就是大对象:如很长的字符串,或者元素数量很庞大的数组。分布式

以下图所示,村民分配到新生代吃内存,年兽被直接分配到老年代。微服务

年兽被直接分配到老年代性能

大量年兽入侵

年兽尝到甜头后,就开始不断地呼叫它的亲戚朋友,大量年兽被分配到了老年代,直接致使老年代的内存空间不足了,以下图所示:

大量年兽入侵

代码演示

咱们用代码来演示下年兽入侵:

  • 建立了 3 个年兽,都占用 10 MB 内存。

public class SpringFestivalOOM {
    public static void main(String[] args) {
        // 年兽1/2/3,都占用 10 MB 内存
        byte[] nianShou1 = new byte[10 * 1024 * 1024];
        byte[] nianShou2 = new byte[10 * 1024 * 1024];
        byte[] nianShou3 = new byte[10 * 1024 * 1024];
    }
}
  • 编译这段程序。

javac SpringFestivalOOM.java
  • 执行这段程序,同时设置堆内存最大为 20 MB。

java -Xms20M -Xmx20M SpringFestivalOOM

由于 3 个年兽占用的内存 30 MB 大于堆的最大内存 20 MB,因此抛出堆内存溢出异常,以下图所示:

堆内存溢出异常

这个时候年哥和村民才发现,原来有这么多年兽占了咱们的地盘,赶快消灭它们!

打走年兽

村民们和年哥凑到一块,讨论了下该如何解决这个问题,究其缘由就是年兽太多了,要减小他们呼朋唤友来吃内存。

放到咱们的 Java 世界中,就是减小大对象的频繁建立

咱们程序员常常出现本地写完代码后没什么问题,到线上后就出问题,极可能的缘由就是线上环境的数据量大,很容易出现大对象的频繁建立,好比大型促销活动时,短期内须要建立大量订单数据,而订单数据又比较复杂,有不少字段,可能会占用大量的内存空间,最终致使频繁触发垃圾回收,而垃圾回收时又会出现 Stop the world 现象,应用程序的性能就降下来了。

守岁

在除夕晚上,都会进行“守岁”,村民们齐聚一堂吃着年夜饭,一块儿等待除夕的钟声。等到天亮再拜访亲戚邻居。

而守岁这个过程只能待在家里,不能作其余事情,因此能够当作是垃圾回收时,其余线程不能工做,也就是 Stop the world 的由来。

以下图所示,除夕以前,村民能够去其余地方活动,除夕夜就只能待在家里守岁了,到了次日早上就能够串门拜年了。

守岁

总结

本篇经过除夕的故事来说解 Java 中垃圾回收机制,因故事较为简单,因此并无对垃圾回收算法进行深刻讲解,本篇只能算做垃圾回收的入门,但愿能给你们带来必定启发做用,对 JVM 很熟的同窗就当学习下除夕的来历吧~

  • 村民做为小对象使用堆区的 新生代,年兽做为大对象直接使用堆区的 老年代

  • 除夕当晚,大量 年兽入侵老年代,致使 堆区内存不足,触发 垃圾回收机制。

  • 守岁就是待在家里守着过新年,而垃圾回收时, 又会中止其余线程,也就是 Stop the world。

  • 避免代码中 频繁复制或建立大对象是必须作的事情,以避免上线后出现问题。

  • 除夕也表明着 辞旧迎新 ,这不正是执行垃圾回收吗?

做者简介:8 年互联网经验,擅长架构设计、分布式、微服务。手写了一套 SpringCloud 实战教程,自主开发了 PMP 刷题小程序和 Java 刷题小程序。回复 pdf 领取。

悟空在这里预估你们除夕快乐,新年快乐,2021 心想事成,好事成双~

本文分享自微信公众号 - 悟空聊架构(PassJava666)。
若有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一块儿分享。

相关文章
相关标签/搜索