JVM 内存溢出 java heap space 您所在的位置:网站首页 java内存溢出后为什么不能继续运行程序 JVM 内存溢出 java heap space

JVM 内存溢出 java heap space

2023-03-12 05:22| 来源: 网络整理| 查看: 265

前段时间公司的项目突然出现了异常,查看日志出现

java.lang.OutOfMemoryError: Java heap space

这不是内存溢出了?当看到这个时候,瞬间想到了JVM调优,这不是面试官最喜欢问的JVM调优? 对JVM没有了解过,刚好项目遇到了,决定学习一波。 首先就是要了解JVM,了解JVM前,需要了解内存模型,类加载机制等;才能更明白的理解JVM,内存模型,类加载机制等,由于时间原因,没有独立的做单独的文章。后续补上。

一:首先了解JVM: JVM它是Java Virtual Machine 的缩写,主要是通过在实际计算机模仿各种计算机功能来实现的,组成部分包括堆、方法区、栈、本地方法栈、程序计算器等部分组成的,其中方法回收堆和方法区是共享区,也就是谁都可以使用,而栈和程序计算器、本地方法栈区是归JVM的。Java能够被称为“一次编译,到处运行”的原因就是Java屏蔽了很多的操作系统平台相关信息,使得Java只需要生成在JVM虚拟机运行的目标代码也就是所说的字节码,就可以在多种平台运行。

二:产生内存溢出,为什么会出现内存溢出,又何为内存泄漏? 1:内存溢出 系统已经不能再分配出你所需要的空间,比如你需要50M的空间,系统只剩40M了,这就叫内存溢出。 例如: 一辆车只能坐5个人,你却要坐feizhou火车似的6个人,掉马路牙子上了,这就是溢出。 就是分配的内存不足以放下数据项序列,称为内存溢出。说白了就是我承受不了那么多,那我就报错。

2:内存泄漏 强引用所指向的对象不会被回收,可能导致内存泄漏,虚拟机宁愿抛出OOM也不会去回收他指向的对象 意思就是你用资源的时候为他开辟了一段空间,当你用完时忘记释放资源了,这时内存还被占用着,一次没关系,但是内存泄漏次数多了就会导致内存溢出。 大白话:就像你谈二个女朋友,当你用完时,屁股没擦干净,这时女朋友还在,一次没关系,但是等你女朋友越来越多了,原本一个星期一天陪一个,到第八个女朋友了,就溢出了。

例子:你向系统申请分配内存进行使用(new),可是使用完了以后却不归还(delete),结果你申请到的那块内存你自己也不能再访问(也许你把它的地址给弄丢了),而系统也不能再次将它分配给需要的程序。就相当于你租了个带钥匙的柜子,你存完东西之后把柜子锁上之后,把钥匙丢了或者没有将钥匙还回去,那么结果就是这个柜子将无法供给任何人使用,也无法被垃圾回收器回收,因为找不到他的任何信息。

一般我们所说的内存泄漏指的是堆内存的泄露,堆内存是指程序从堆中分配的,大小随机的用完后必须显示释放的内存,C++/C中有free函数可以释放内存,java中有垃圾回收机制不用程序员自己手动调用释放

如果这块内存不释放,就不能再用了,这就叫内存泄漏了。

3:内存溢出,内存泄漏的概念

内存溢出 : out of memory,是指程序在申请内存时,没有足够的内存空间供其使用,出现out of memory;比如申请了一个integer,但给它存了long才能存下的数,那就是内存溢出。

内存泄露 : memory leak,是指程序在申请内存后,无法释放已申请的内存空间,一次内存泄露危害可以忽略,但内存泄露堆积后果很严重,无论多少内存,迟早会被占光。

memory leak会最终会导致out of memory! 内存溢出就是你要求分配的内存超出了系统能给你的,系统不能满足需求,于是产生溢出

内存泄露是指无用对象(不再使用的对象)持续占有内存或无用对象的内存得不到及时释放,从而造成的内存空间的浪费称为内存泄露。内存泄露有时不严重且不易察觉,这样开发者就不知道存在内存泄露,但有时也会很严重,会提示你Out of memory。那么,Java内存泄露根本原因是什么呢?长生命周期的对象持有短生命周期对象的引用就很可能发生内存泄露,尽管短生命周期对象已经不再需要,但是因为长生命周期对象持有它的引用而导致不能被回收,这就是java中内存泄露的发生场景。

看完概念,继续往下看原因

4:内存溢出的原因

(1)如你的代码,循环中一直产生过多重复的对象实体。— 如批量导出成千上万的数据 (2)死循环,这个情况可能不是项目上线就会出现的,可能代码中有条件判断,恰到条件等原因出现死 循环 (3)内存中加载数据库的量太大,就如同第一点的导出,一次从数据库取出过多数据。 (4)还有常见的集合,例如用集合类有对象的引用,导致使用完后未清空,使得JVM不能回收; (5)还有启动JVM参数设内存值的大小的原因 (6)如使用各种第三方JAR包,如一些第三方JAR包工具类等。 (7)单例模式 (8)各种连接啊,如:数据库连接啊,IO连接啊,网络连接啊 (9)流没有关闭 (10)静态对象

上述某些详细解释: 第七点:单例模式 如果单例对象持有外部对象的引用,那么这个外部对象将不能被jvm正常回收,导致内存泄露不正确使用单例模式是引起内存泄露的一个常见问题,单例对象在被初始化后将在JVM的整个生命周期中存在(以静态变量的方式),如果单例对象持有外部对象的引用,那么这个外部对象将不能被jvm正常回收,导致内存泄露。 看如下例子:

class Test{ public Test(){ SingletonTest.getInstance().setTest(this); } .... } // SingletonTest 类采用单例模式 class SingletonTest{ private Test test ; private static SingletonTest instance=new SingletonTest(); public SingletonTest(){} public static SingletonTest getInstance(){ return instance; } public void setTest(Test test ){ this.test =test ; } //getter... }

第八点:连接 比如数据库连接(dataSourse.getConnection()),网络连接(socket)和io连接,除非其显式的调用了其close()方法将其连接关闭,否则是不会自动被GC 回收的。对于Resultset 和Statement 对象可以不进行显式回收,但Connection 一定要显式回收,因为Connection 在任何时候都无法自动回收,而Connection一旦回收,Resultset 和Statement 对象就会立即为NULL。但是如果使用连接池,情况就不一样了,除了要显式地关闭连接,还必须显式地关闭Resultset Statement 对象(关闭其中一个,另外一个也会关闭),否则就会造成大量的Statement 对象无法释放,从而引起内存泄漏。这种情况下一般都会在try里面取的连接,在finally里面释放连接。

第九点:流 开发中,我们经常使用到流,如OutputStream,BufferedReader啊等等。开发中,我们难免会忘记关闭流,这样也会导致内存泄漏。因为每个流在操作系统层面都对应了打开的文件句柄,流没有关闭,会导致操作系统的文件句柄一直处于打开状态,而jvm会消耗内存来跟踪操作系统打开的文件句柄。

第十点:静态对象 静态集合类引起内存泄露(static 对象是不会被GC回收的): 集合类,如HashMap、Set、ArrayList、Vector等它们是内存泄漏的常见位置。如果将他们声明为static,那么它将拥有和主程序一样的生命周期,如果他们里面放置了大量对象(引用的关系),当这些对象不在使用时,因为HashMap,集合等是全局的static类型,那么垃圾回收将无法处理这些不在使用的对象,从而造成了内存泄漏。

如下面的例子代码:

class User{ } public class MemoryLeak{ static List list = new ArrayList(); public static void main(String[] args) throws InterruptedException{ for(int i =0;i


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有