java程序员遇到的问题_Java 程序员平时最常遇到的故障:系统OOM (一)

作为 Java 程序员而言,先不考虑自己系统外部依赖的缓存、消息队列、数据库等等东西挂掉,就我们自己系统本身而言,最常见的挂掉的原因是什么?

其实就是系统OOM,也就是所谓的内存溢出!

什么是内存溢出?在哪些区域会发生内存溢出?

运行一个 Java 系统就是运行一个JVM进程

首先的话呢,大家得先搞明白一个事情,就是我们平时说启动一个Java系统,其实本质就是启动一个JVM进程。

咱们就用最最基本的情况来给大家演示一下好了,比如说下面的一段代码,是每个Java初学者都会写的一段代码:

b4cf6021f4193d1bb683a3e9b23e9d8a.png

那么大家知道,当你在Eclipse或者Intellij IDEA中写好这个代码,然后通过IDE来运行这个代码的时候,会发生哪些事情吗?

首先,我们专栏最早的几篇文章就给大家说过,我们写好的代码他都是后缀为“.java”的源代码,这个代码是不能运行的。

所以第一步就是这份“.java”源代码文件必须先编译成一个“.class”字节码文件,这个字节码文件才是可以运行的,如下图所示。

a922a0eaf29730bc47b321d7308ccd62.png

接着对于这种编译好的字节码文件,比如HelloWorld.class,如果里面包含了main方法,接下来我们就可以用“java命令”来在命令行执行这个字节码文件了

实际上一旦你执行“java命令”,相当于就会启动一个JVM进程。这个JVM进程就会负责去执行你写好的那些代码,如下图所示。

a3f2bca461169616d0b5e9763241caa7.png

所以首先要清楚第一点,运行一个Java系统,本质上就是启动一个JVM进程,这个JVM进程负责来执行你写好的一大堆代码。只要你的Java系统中包含一个main方法,接着JVM进程就会从你指定的这个main方法入手,开始执行你写的代码。

到底执行哪些代码:JVM得加载你写的类

Java是一个面向对象的语言,所以最最基本的代码组成单元就是一个一个的类,平时我们说写Java代码,不就是写一个一个的类吗?是不是。

然后在一个一个的类里我们会定义各种变量,方法,数据结构,通过if else之类的语法,写出来各种各样的系统业务逻辑,这就是所谓的编程了。

所以JVM既然要执行你写的代码,首先当然得把你写好的类加载到内存里来啊!

所以JVM的内存区域里大家都知道,有一块区域叫做永久代,当然JDK 1.8以后都叫做Metaspace了,我们也用最新的说法好了。

这块内存区域就是用来存放你系统里的各种类的信息的,包括JDK自身内置的一些类的信息,都在这块区域里。

JVM有类加载器和一套类加载的机制,我们在专栏最开始的时候都说过了,这里不再赘述,他会负责把我们写好的类从编译好的“.class”字节码文件里加载到内存里来,如下图。

33674c1cb62dcf43c95e859ede463a5b.png

好,那么既然有这么一块Metaspace区域是用来存放类信息的,那是不是有可能在这个Metaspace区域里就会发生OOM?

没错,是有这种可能的。

Java虚拟机栈:让线程执行各种方法

大家都知道,我们写好的那些Java代码虽然是一个一个的类,但是其实核心的代码逻辑一般都是封装在类里面的各种方法中的

比如JVM已经加载了我们写好的HelloWorld类到内存里了,接着怎么执行他里面的代码呢?

Java语言中的一个通用的规则,就是一个JVM进程总是从main方法开始执行的,所以我们既然在HelloWorld中写了一个main()方法,那么当然得执行这个方法中的代码了。

但是等一等,JVM进程里的谁去执行main()方法的代码?

其实我们所有的方法执行,都必须依赖JVM进程中的某个线程去执行,你可以理解为线程才是执行我们写的代码的核心主体。

JVM进程启动之后默认就会有一个main线程,这个main线程就是专门负责执行main()方法的。

大家如下图所示。

50cc6e53cb3c1b23d0fc77ccc11537ed.png

现在又有一个问题了,在main()方法里定义了一个局部变量,“message”,那么大家回忆一下,这些方法里的局部变量可能会有很多,那么这些局部变量是放在哪里的呢?

很简单,每个线程都有一个自己的虚拟机栈,就是所谓的栈内存。

然后这个线程只要执行一个方法,就会为方法创建一个栈桢,将栈桢放入自己的虚拟机栈里去,然后在这个栈桢里放入方法中定义的各种局部变量,如下图所示

991722fee500e0c7cef34a0315792a15.png

好,现在问题来了,大家如果还记得之前我们讲过的一个参数,应该都知道,我们是可以设置JVM中每个线程的虚拟机栈的内存大小的,一般是设置为1MB。

那么既然每个线程的虚拟机栈的内存大小是固定的,是否可能会发生虚拟机栈的内存溢出?

没错,所以第二块可能发生OOM的区域,就是每个线程的虚拟机栈内存。

堆内存:放我们创建的各种对象

最后我们知道,我们写好的代码里,特别在一些方法中,可能会频繁的创建各种各样的对象,这些对象都是放在堆内存里的,如下图所示。

61cb920c5c08bd83c7d1b559ccfa17c1.png

而且我们通过之前的学习,也都知道了一点,通常我们在JVM中分配给堆内存的空间其实一般是固定的

既然如此,我们还不停在堆内存里创建对象,是不是说明,堆内存也有可能会发生内存溢出?

没错,第三块可能发生内存溢出的区域,就是堆内存空间!

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值