Java内存溢出与栈溢出

标签: java 内存 溢出 | 发表时间:2015-01-23 19:02 | 作者:hu1991die
出处:http://blog.csdn.net

一、背景知识


1、JVM体系结构




2、JVM运行时数据区




3、JVM内存模型


JVM运行时内存 = 共享内存区 + 线程内存区




3-1、共享内存区


共享内存区 = 持久带 + 堆

持久带 = 方法区 + 其他

堆 = Old Space + Young Space

Young Space = Eden + S0 + S1




3-1-1、持久代


JVM用持久带(Permanent Space)实现方法区,主要存放所有已加载的类信息,方法信息,常量池等等。

可通过-XX:PermSize和-XX:MaxPermSize来指定持久带初始化值和最大值。

Permanent Space并不等同于方法区,只不过是Hotspot JVM用Permanent Space来实现方法区而已,有些虚拟机没

有Permanent Space而用其他机制来实现方法区。


3-1-2、堆


堆(heap),主要用来存放类的对象实例信息(包括new操作实例化的对象和定义的数组)。

堆分为Old Space(又名,Tenured Generation)和Young Space。

Old Space主要存放应用程序中生命周期长的存活对象;

Eden(伊甸园)主要存放新生的对象;

S0和S1是两个大小相同的内存区域,主要存放每次垃圾回收后Eden存活的对象,作为对象从Eden过渡到Old Space

的缓冲地带(S是指英文单词Survivor Space)。

堆之所以要划分区间,是为了方便对象创建和垃圾回收,后面垃圾回收部分会解释。


3-2、线程内存区


线程内存区=单个线程内存+单个线程内存+.......

单个线程内存=PC Regster+JVM栈+本地方法栈

JVM栈=栈帧+栈帧+.....

栈帧=局域变量区+操作数区+帧数据区




在Java中,一个线程会对应一个JVM栈(JVM Stack),JVM栈里记录了线程的运行状态。

JVM栈以栈帧为单位组成,一个栈帧代表一个方法调用。栈帧由三部分组成:局部变量区、操作数栈、帧数据区。


二、堆溢出


堆(Heap)是Java存放对象实例的地方。

堆溢出可以分为以下两种情况,这两种情况都会抛出OutOfMemoryError:java heap space异常:


1、内存泄漏


内存泄漏是指对象实例在新建和使用完毕后,仍然被引用,没能被垃圾回收释放,一直积累,直到没有剩余

内存可用。

如果内存泄露,我们要找出泄露的对象是怎么被GC ROOT引用起来,然后通过引用链来具体分析泄露的原因。

分析内存泄漏的工具有:Jprofiler,visualvm等。


示例代码:

package com.jvm;

import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

/**
 * 内存泄漏
 * @author feizi
 * @time 2015-1-23上午8:42:53
 */
public class OOMTest {

	public static void main(String[] args) {
		
		List<UUID> list = new ArrayList<UUID>();
		while(true){
			list.add(UUID.randomUUID());
		}
	}

}



看看控制台的输出结果,因为我这边的JVM设置的参数内存足够大,所以需要等待一定的时间,才能看到效果:






如果是用CMD命令行,就可以自己指定参数编译运行了,这样效果就更快一些:

通过下列命令运行程序,注意先要用javac命令将.java源文件编译成.class类字节码文件。


java -Xms10M -Xmx10M -XX:-UseGCOverheadLimit OOMTest


2、内存溢出


内存溢出是指当我们新建一个实力对象时,实例对象所需占用的内存空间大于堆的可用空间。

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


示例代码:

package com.jvm;

import java.util.ArrayList;
import java.util.List;

/**
 * 内存溢出
 * @author feizi
 * @time 2015-1-23上午8:56:22
 */
public class OOMTest_1 {
	public static void main(String args[]){
		List<byte[]> byteList = new ArrayList<byte[]>();
		byteList.add(new byte[1000 * 1024 * 1024]);
	}
}



看看控制台的运行效果:




使用CMD命令行指定参数运行:


java -verbose:gc -Xmn10M -Xms20M -Xmx20M -XX:+PrintGC OOMTest_1




三、线程栈


栈(JVM Stack)存放主要是栈帧( 局部变量表, 操作数栈 , 动态链接 , 方法出口信息 )的地方。注意区分栈和栈帧:栈里包含栈帧。

与线程栈相关的内存异常有两个:

a)、StackOverflowError(方法调用层次太深,内存不够新建栈帧)

b)、OutOfMemoryError(线程太多,内存不够新建线程)


1、java.lang.StackOverflowError


栈溢出抛出java.lang.StackOverflowError错误,出现此种情况是因为方法运行的时候,请求新建栈帧时,

栈所剩空间小于战帧所需空间。

例如,通过递归调用方法,不停的产生栈帧,一直把栈空间堆满,直到抛出异常 :


示例代码:

package com.jvm;
/**
 * 栈溢出
 * @author feizi
 * @time 2015-1-23上午9:13:11
 */
public class SOFTest {

	public void stackOverFlowMethod(){
		stackOverFlowMethod();
	}
	
	/**
	 * 通过递归调用方法,不停的产生栈帧,一直把栈空间堆满,直到抛出异常 :
	 * @param args
	 */
	public static void main(String[] args) {
		SOFTest sof = new SOFTest();
		sof.stackOverFlowMethod();
	}

}


看看控制台运行的效果:





作者:hu1991die 发表于2015-1-23 11:02:56 原文链接
阅读:38 评论:0 查看评论

相关 [java 内存 溢出] 推荐:

Java 内存溢出排查

- - ImportNew
Java OOM 毫无疑问是开发人员常见并且及其痛恨的问题,但是任何服务的开发都没法避免 OOM. 因此,OOM 的排查及定位是每个 Java 工程师都必备的技能. 在使用 scala 开发的一个 web 服务,在用户使用中,经常出现:  java.lang.OutOfMemoryError: Java heap space .

Java内存溢出与栈溢出

- - CSDN博客推荐文章
JVM运行时内存 = 共享内存区 + 线程内存区. 共享内存区 = 持久带 + 堆. 持久带 = 方法区 + 其他. 堆 = Old Space + Young Space. JVM用持久带(Permanent Space)实现方法区,主要存放所有已加载的类信息,方法信息,常量池等等. 可通过-XX:PermSize和-XX:MaxPermSize来指定持久带初始化值和最大值.

Java 内存区域与内存溢出

- - CSDN博客综合推荐文章
Java虚拟机在执行Java程序的过程中会把他所管理的内存划分为若干个不同的数据区域. Java虚拟机规范将JVM所管理的内存分为以下几个运行时数据区:程序计数器,Java虚拟机栈,本地方法栈,Java堆,方法区. 下面详细阐述各数据区所存储的数据类型. 程序计数器(Program Counter Register).

Java 堆内存溢出梗概分析

- - ITeye资讯频道
原文:Java Out of Memory Heap Analysis. 链接: https://dzone.com/articles/java-out-of-memory-heap-analysis. 译者:dreamanzhao, 无若. 任何使用过基于 Java 的企业级后端应用的软件开发者都会遇到过这种低劣、奇怪的报错,这些报错来自于用户或是测试工程师: java.lang.OutOfMemoryError:Java heap space.

java 内存溢出 栈溢出的原因与排查方法

- - 互联网 - ITeye博客
 1、 内存溢出的原因是什么.       内存溢出是由于没被引用的对象(垃圾)过多造成JVM没有及时回收,造成的内存溢出. 如果出现这种现象可行代码排查:.     一)是否App中的类中和引用变量过多使用了Static修饰 如public staitc Student s;在类中的属性中使用 static修饰的最好只用基本类型或字符串.

java内存泄露和内存溢出区别

- - 互联网 - ITeye博客
虽然jvm可以通过GC自动回收无用的内存,但是代码不好的话仍然存在内存溢出的风险. 最近在网上搜集了一些资料,现整理如下:. 一、为什么要了解内存泄露和内存溢出. 1、内存泄露一般是代码设计存在缺陷导致的,通过了解内存泄露的场景,可以避免不必要的内存溢出和提高自己的代码编写水平;. 2、通过了解内存溢出的几种常见情况,可以在出现内存溢出的时候快速的定位问题的位置,缩短解决故障的时间.

Java内存溢出问题的定位过程

- - Java - 编程语言 - ITeye博客
相信通过写java程序讨生活的人对内存溢出并不陌生,如下文字的出现更是让人恼火:. 尤其当应用服务器(Java容器)出现上述情况更是让人有一种天塌下来的感觉.    好的编码实践可能会大大降低内存溢出的产生.    本文并不是写如何规避内存溢出,但是我还是要介绍一下如何能够尽量规避内存溢出:. 找几个资深程序猿(或者整个项目组讨论后)写一个Java编码规范,让项目组成员尽量遵守.

译文:解密Java内存溢出之持久代

- - 研发管理 - ITeye博客
       垃圾回收是Java程序员了解最少的一部分. 他们认为Java虚拟机接管了垃圾回收,因此没必要去担心内存的申请,分配等问题. 但是随着应用越来越复杂,垃圾回收也越来越复杂,一旦垃圾回收变的复杂,应用的性能将会大打折扣. 所以,Java程序员了解垃圾回收的机制并且知道怎样解决“内存溢出”问题会有很大的益处.

Java常见问题分析(内存溢出、内存泄露、线程阻塞等)

- - Java - 编程语言 - ITeye博客
Java垃圾回收机制(GC) . 堆内存3代分布(年轻代、老年代、持久代) . ML(内存泄露) OOM(内存溢出)问题现象及分析 . IBM DUMP分析工具使用介绍. Java应用CPU、线程问题分析. Java垃圾回收机制(GC). 1.GC机制作用 . 1.1 JVM自动检测和释放不再使用的对象内存 .

使用JProfiler解决Java应用程序内存溢出问题实例

- - Java - 编程语言 - ITeye博客
    前段时间基于OpenJms部署了一个消息中间件服务器,通过主题订阅模式在各个消息节点之间传递信息,但是某个类型的消息节点长时间运行后出现了内存溢出问题,最后使用JProfiler的基本线程监测功能找到问题所在,并且进行解决. Java 版本 java version "1.7.0_40". JProfiler 版本 v8.0.7.