文档章节

Java内存溢出与栈溢出

shanxi_liyong
 shanxi_liyong
发布于 2015/02/11 11:33
字数 1256
阅读 31
收藏 1

一、背景知识


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();
	}

}


看看控制台运行的效果:



© 著作权归作者所有

共有 人打赏支持
上一篇: JFBlog
下一篇: ClassLoader
shanxi_liyong
粉丝 10
博文 106
码字总数 37225
作品 0
太原
程序员
私信 提问
JVM之Java内存区域与内存溢出异常

Java的JVM可以自动管理内存,包括内存动态分配和垃圾收集等。 简介 JVM在执行Java程序的过程中会把它所管理的内存划分为若干个不同的数据区域。这些区域都有各自的用途,以及创建和销毁的时间...

Jeffbond
2017/04/08
0
0
【Java】内存问题——内存溢出

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/tr1912/article/details/82261379 模拟内存溢出 我们通过自己写代码,模拟一下两种内存溢出的情况,一种是堆内...

王啸tr1912
08/31
0
0
《深入理解Java虚拟机》之内存溢出(2)

通过简单的小例子程序,演示java虚拟机各部分内存溢出情况: (1).java堆溢出: Java堆用于存储实例对象,只要不断创建对象,并且保证GC Roots到对象之间有引用的可达,避免垃圾收集器回收实例...

lixiyuan
2014/04/10
0
0
JAVA内存管理和JVM运行机制、垃圾回收、内存调优

一、JAVA内存管理 java是跨平台语言,java预编译.class文件放置JVM虚拟机中运行; Java的内存结构,也就是运行时的数据区域 运行时数据区 方法区:常量池、变量等存储地方;(持久区) 堆:实...

盼望明天
08/03
0
0
java虚拟机运行时的内存分类以及出现异常分析(jvm之一)

java虚拟机所管理的内存包括以下几个运行时数据区域: 方法区(Method Area):线程共享的,存放已被虚拟机记载的类信息、常量、静态变量等数据。“永久代(Permanent Generation)” 虚拟机...

zhengDavid
2012/06/13
0
0

没有更多内容

加载失败,请刷新页面

加载更多

firewalld

1. firewalld 是什么 CentOS中默认是有 firewalld, iptables, etablesd firewalld 是 CentOS7/RadHat7 中默认的防火墙管理工具. firewalld 工具用来管理里netfilter, 不过底层还是调用的还是...

Fc丶
21分钟前
1
0
Java 源代码和 C 源代码的运行区别

与其他程序的执行方式和编译方式不同。 Java 源代码需要进行编译成字节码后在 Java 虚拟机上运行,这样 Java 程序能够保持独立性和跨平台功特性。 请参考下图。 https://www.cwiki.us/pages...

honeymose
今天
4
0
Apache限定目录解析PHP,限制user_agent,PHP相关的配置

Apache限定目录解析PHP 配置前访问upload/index.php [root@test-a ~]# curl -x192.168.77.139:80 'www.test.com/upload/index.php'This is upload diretory 配置,/usr/local/apache2.4/......

野雪球
今天
5
0
java.util.Concurrent.Exchanger源码

类图 源码: package java.util.concurrent;import java.util.concurrent.atomic.AtomicInteger;import java.util.concurrent.atomic.AtomicReference;import java.util.concurrent......

狼王黄师傅
今天
6
0
Kubernetes里的secret最基本的用法

Secret解决了密码、token、密钥等敏感数据的配置问题,使用Secret可以避免把这些敏感数据以明文的形式暴露到镜像或者Pod Spec中。 Secret可以以Volume或者环境变量的方式使用。 使用如下命令...

JerryWang_SAP
昨天
5
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部