JAVA的内存分为方法区、虚拟机栈、本地方法栈、堆、程序计数器五个部分,除程序计数器外,其它部分都可能出现内存溢出OOM(OutOfMemeryError)。

1、内存溢出和内存泄漏的区别
内存溢出 (Out Of Memory):是指程序在申请内存时,没有足够的内存空间供其使用,出现Out Of Memory。
内存泄露 (Memory Leak):是指程序在申请内存后,由于某种原因无法释放已申请的内存空间,导致这块内存无法再次被利用,造成系统内存的浪费。一次内存泄露危害可以忽略,但内存泄露堆积的后果很严重,无论多少内存,迟早会被占光。
2、内存溢出详解

2.1.Java虚拟机栈与本地方法栈

每个线程栈的大小控制参数时 -Xss。

Java虚拟机在栈中定义了两种异常,StrackOverFlowError和OutOfMemoryError:unable to create new native thread。当请求栈的深度大于java虚拟机所允许的最大深度则抛出StrackOverFlowError;如果Java虚拟机在栈扩展时,没有申请到足够的空间时,则抛出OutOfMemoryError:unable to create new native thread。

StrackOverFlowError:单线程内占用内存超过了栈的大小-Xss

出现场景

一、局部数组或集合过大。一般出现在大查询或大导出的情况下。

二、方法调用太多。一般出现在递归调用层次太多或死循环时。

三、指针或数组越界。这种情况最常见,例如进行字符串拷贝,或处理用户输入等等。

解决方式

优化程序、减少方式的调用、增大-Xss参数

代码模拟

package com.leedalong.jvm;//-Xss64k时,depth=816
//-Xss128k时,depth=2896
//-Xss256k时,depth=5935
//-Xss512k时,depth=19292
//-Xss1024k时,depth=38631
//异常信息

//Exception in thread "main" java.lang.StackOverflowError
//at com.leedalong.jvm.StackSOFTest.sofMethod(StackSOFTest.java:14)
//at com.leedalong.jvm.StackSOFTest.sofMethod(StackSOFTest.java:14)

public class StackSOFTest {int depth = 0;public void sofMethod() {depth++;sofMethod();}public static void main(String[] args) {StackSOFTest test = null;try {test = new StackSOFTest();test.sofMethod();} finally {System.out.println("递归次数:" + test.depth);}}
}

  

OutOfMemoryError:unable to create new native thread:多线程占用的内存超过了可用内存(进程可用内存(32位操作系统时为2G)-Xmx-MaxPermSize-虚拟机本身耗费的内存和程序计数器使用的内存)

解决方式

减少线程数量、降低-Xss的大小(即减少每个线程拥有的内存大小)、降低-Xmx以及MaxPermSize的大小扩大留给栈的空间

代码模拟

package com.leedalong.jvm;
//-Xms600m
//-Xmx600m
//-Xss10m
/*Exception in thread "main" java.lang.OutOfMemoryError: unable to create new native thread
at java.lang.Thread.start0(Native Method)
at java.lang.Thread.start(Thread.java:714)
at com.leedalong.jvm.StackOOMTest.oomMethod(StackOOMTest.java:17)
at com.leedalong.jvm.StackOOMTest.main(StackOOMTest.java:7)*/
public class StackOOMTest {public static void main(String[] args) {StackOOMTest test = new StackOOMTest();test.oomMethod();}public void oomMethod(){while(true){new Thread(new Runnable() {@Overridepublic void run() {loopMethod();}}).start();}}private void loopMethod(){try {Thread.sleep(100000);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}
}

  

2.方法区内存溢出

方法区也是所有线程共享。主要用于存储类的信息、常量池、方法数据、方法代码等。方法区逻辑上属于堆的一部分,但是为了与堆进行区分,通常又叫“非堆”。

绝大部分 Java 程序员应该都见过 "java.lang.OutOfMemoryError: PermGen space "这个异常。这里的 “PermGen space”其实指的就是方法区。不过方法区和“PermGen space”又有着本质的区别。前者是 JVM 的规范,而后者则是 JVM 规范的一种实现,并且只有 HotSpot 才有 “PermGen space”,而对于其他类型的虚拟机,如 JRockit(Oracle)、J9(IBM) 并没有“PermGen space”。

JDK8之前方法区的实现为永久代,大小通过-XX:PermSize=64M-XX:MaxPermSize=128M控制。

JDK8开始方法区的实现为元空间,大小通过-XX:MetaspaceSize=8m-XX:MaxMetaspaceSize=8m控制。

当持久带溢出的时候抛出 java.lang.OutOfMemoryError: PermGen space【JDK8之前】、java.lang.OutOfMemoryError: Metaspace【JDK8】

出现场景

一、在Spring以及Hibernate,Mybatis中都会使用GeneratedConstructorAccessor、动态代理以及CGLib字节码增强技术的等动态生成类,那么就需要强大的方法区来支撑。

二、运行时常量池溢出【java8的常量池已经移到了堆内存中】

三、使用一些应用服务器的热部署的时候,我们就会遇到热部署几次以后发现内存溢出了,这种情况就是因为每次热部署的后,原来的Class没有被卸载掉。

解决方式

一、增加java虚拟机中的XX:PermSize和XX:MaxPermSize参数的大小,其中XX:PermSize是初始永久保存区域大小,XX:MaxPermSize是最大永久保存区域大小。如针对tomcat6.0,在catalina.sh 或catalina.bat文件中一系列环境变量名说明结束处(大约在70行左右) 增加一行:
JAVA_OPTS=" -XX:PermSize=64M -XX:MaxPermSize=128m"
如果是windows服务器还可以在系统环境变量中设置。感觉用tomcat发布sprint+struts+hibernate架构的程序时很容易发生这种内存溢出错误。使用上述方法,我成功解决了部署ssh项目的tomcat服务器经常宕机的问题。
二、清理应用程序中web-inf/lib下的jar,如果tomcat部署了多个应用,很多应用都使用了相同的jar,可以将共同的jar移到tomcat共同的lib下,减少类的重复加载。这种方法是网上部分人推荐的,我没试过,但感觉减少不了太大的空间,最靠谱的还是第一种方法。

代码模拟

package com.leedalong.jvm;import java.lang.reflect.Method;import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
//-XX:MetaspaceSize=8m
//-XX:MaxMetaspaceSize=8m
/*** 从jdk8开始,方法区的实现不再使用永久代,而是使用元空间* @author 592815**/
public class MethodAreaOOMTest {public static void main(String[] args) {int i = 0;JVMParamUtil.printJVMParam();try {while (true) {Enhancer enhancer = new Enhancer();enhancer.setSuperclass(OOMObject.class);enhancer.setUseCache(false);enhancer.setCallback(new MethodInterceptor() {@Overridepublic Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy)throws Throwable {return proxy.invokeSuper(obj, args);}});enhancer.create();i++;}} finally {System.out.println("运行次数:" + i);}}static class OOMObject {public void print() {System.out.println("execute!");}}
}

  

3.堆内存溢出

堆的大小通过-Xms和-Xmx设置

堆内存溢出的时候,虚拟机会抛出 java.lang.OutOfMemoryError:java heap space

出现场景

创建对象时如果没有可以分配的堆内存,JVM就会抛出OutOfMemoryError:java heap space异常

解决方式

首先需要分清是内存溢出还是内存泄露

(1)如果是内存溢出,则通过 调大 -Xms,-Xmx参数。
(2)如果是内存泄露,则看对象如何被 GC Root 引用。

出现此种情况的时候,我们需要根据内存溢出的时候产生的 dump 文件来具体分析(需要增加 -XX:+HeapDump
OnOutOfMemoryError jvm启动参数)。出现此种问题的时候有可能是内存泄漏,也有可能是内存溢出了。

1、配置方法

-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=${目录}。
2、参数说明

(1)-XX:+HeapDumpOnOutOfMemoryError参数表示当JVM发生OOM时,自动生成DUMP文件。

(2)-XX:HeapDumpPath=${目录}参数表示生成DUMP文件的路径,也可以指定文件名称,例如:-XX:HeapDu
mpPath=${目录}/java_heapdump.hprof。如果不指定文件名,默认为:java_<pid><date><time>_heapDu
mp.hprof。
如果是内存泄漏,我们要找出内存泄漏的对象是怎么被GC ROOT引用起来,然后通过引用链来具体分析泄露的
原因。

如果出现了内存溢出问题,这往往是程序本生需要的内存大于了我们给虚拟机配置的内存,这种情况下,我
们可以采用调大-Xmx来解决这种问题。

代码模拟

package com.leedalong.jvm;import java.util.ArrayList;
import java.util.List;//-Xms20m
//-Xmx20m
public class HeapOOMTest {public static void main(String[] args) {List<byte[]> list = new ArrayList<>();int i=0;while(true){list.add(new byte[5*1024*1024]);System.out.println("分配次数:"+(++i));}}
}

  

转载于:https://www.cnblogs.com/freelymen/p/9294774.html

3.JAVA内存溢出相关推荐

  1. Java内存溢出详解之Tomcat配置

    Java内存溢出详解 转自:http://elf8848.iteye.com/blog/378805 一.常见的Java内存溢出有以下三种: 1. java.lang.OutOfMemoryError ...

  2. SpringBoot如何处理java内存溢出

    在上线的项目中,本地测试没有问题,部署上去就会出现java 内存溢出 java.lang.OutOfMemoryError: Java heap space 解决方案: -Xms512m -Xmx51 ...

  3. java 二维数组内存溢出_模拟Java内存溢出

    本文通过修改虚拟机启动参数,来剖析常见的java内存溢出异常(基于jdk1.8). 修改虚拟机启动参数 这里我们使用的是IDEA集成开发环境,选择Run/Debug Configurations 然后 ...

  4. Java内存溢出详解

    Java内存溢出详解 一.常见的Java内存溢出有以下三种: 1. java.lang.OutOfMemoryError: Java heap space ----JVM Heap(堆)溢出 JVM在 ...

  5. Java内存溢出分析

    内存溢出与数据库锁表的问题,可以说是开发人员的噩梦,一般的程序异常,总是可以知道在什么时候或是在什么操作步骤上出现了异常,而且根据堆栈信息也很容易定位到程序中是某处出现了问题.内存溢出与锁表则不然,一 ...

  6. Java 内存溢出(java.lang.OutOfMemoryError)的常见情况和处理方式总结

    导致OutOfMemoryError异常的常见原因有以下几种: 1.内存中加载的数据量过于庞大,如一次从数据库取出过多数据: 2.集合类中有对对象的引用,使用完后未清空,使得JVM不能回收: 3.代码 ...

  7. java内存溢出分析工具:jmap使用实战

    java内存溢出分析工具:jmap使用实战 在一次解决系统tomcat老是内存撑到头,然后崩溃的问题时,使用到了jmap.  1 使用命令  在环境是linux+jdk1.5以上,这个工具是自带的,路 ...

  8. tomcat java内存_[Tomcat]Java内存溢出详解Tomcat内存设置

    Java内存溢出详解 一.常见的Java内存溢出有以下三种: 1.java.lang.OutOfMemoryError: Java heap space ----JVM Heap(堆)溢出 JVM在启 ...

  9. Java基础学习总结(30)——Java 内存溢出问题总结

    Java中OutOfMemoryError(内存溢出)的三种情况及解决办法 相信有一定java开发经验的人或多或少都会遇到OutOfMemoryError的问题,这个问题曾困扰了我很长时间,随着解决各 ...

  10. Java内存溢出异常(下)

    此篇是上一篇文章Java内存溢出异常(上)的续篇,没有看过的同学,可以先看一下上篇.本篇文章将介绍剩余的两个溢出异常:方法区和运行时常量池溢出. 方法区和运行时常量池溢出 这部分为什么会放在一起呢?在 ...

最新文章

  1. geth安装失败,双击后不显示或等待很久后报错
  2. php抓取页面400错误
  3. mysql key uni_uni app 踩坑实录
  4. 小程序引用其他页面js_来聊聊小程序页面之间如何通信
  5. Android之封装倒计时页面
  6. 二叉树前序遍历、中序遍历、后序遍历手稿
  7. R语言学习笔记:矩阵与数组(array)
  8. 数据结构之队列java版
  9. 惠普传真服务器位置,惠普传真机的使用方法
  10. matlab随机抽样模拟,随机抽样一致性算法(matlab)
  11. 销售计算机流程图,flowchart_请问在电脑WORD中怎样画流程图?
  12. 信号与系统 傅里叶变换 拉普拉斯变换 z变换所有公式和性质 三个变换的联系 整理
  13. 重装Win10系统之U盘启动盘的制作(详细教程)
  14. 最小二乘法曲线拟合原理与实现
  15. Red Hat Enterprise Linux Server release 7.4 (Maipo) 安装mysql5.7.36
  16. 你有一桶果冻,其中有黄色、绿色、红色三种,闭上眼睛抓取同种颜色的两个。 抓取多少个就可以确定你肯定有两个同一颜色的果冻?(5秒-1分钟)
  17. java基础知识总结,javaweb参考资料大全
  18. 云南2018年GDP增长8.9% 较2017年增长速度有所下降
  19. 谷歌 不支持 activeX插件
  20. 大数据赋能,如何精细化运营?

热门文章

  1. 动态修改log4net设置
  2. 调查:Win7是勒索病毒的重灾区 XP受影响不足0.1%
  3. mysql主从同步开启后的iptables的设定问题
  4. 有线网络高可用项目实施方案(更新中)
  5. 通过Process调用桌面程序
  6. 一起谈.NET技术,基于Visual Studio 2010 阐述C#4个特性
  7. 你还在 Docker 中跑 MySQL?恭喜你,好下岗了!
  8. 7 款神秘的开源中间件!
  9. 你们要的Windows IDEA 快捷键终极大全,速度收藏!
  10. 一个工作三年左右的Java程序员跟大家分享从业心得