JVM深入学习笔记三:JVM 内存模型

1. JVM运行时内存 图

程序计数器

当前线程执行的字节码的行号指示器,线程通过这部分来选择下一条指令,通过这个部分来实现分支,循环等操作。没有OOM,没有参数可以控制

Java虚拟机栈

描述方法执行的内存区,一个方法的执行就是形成一个栈帧入栈和出栈的过程

栈帧(局部变量表,操作数栈, 动态链接),  局部变量表就是参数和一些方法内的局部变量,操作数栈是方法中的一些操作的运算用的字节码, 动态链接是区别于静态链接的部分,主要包含一些执行信息和资源

包含了两种异常: 线程请求的栈深度大于虚拟机所允许的深度,将抛出StackOverflowError异常。

虚拟机栈扩展是无法申请到足够的内存时抛出OutOfMemoryError异常

-Xss 设置一个线程中栈帧的大小总和

-Xss 参数设置 一个线程中栈帧的大小总和

本地方法栈

跟Java虚拟机栈功能类似,HotSpot中是合并了的

Java堆

GC堆,使用分代收集的算法。 会抛出OOM异常,用-Xmx(最大堆大小) -Xms(初始堆大小)

方法区

 存储加载的类信息、常量、静态变量、即时编译器编译后的代码(也就是机器码)。

HotSpot中可能会被称为永久带,但是实际上很多的JVM实现中是没有永久带这个概念的,HotSpot也在计划取消这个定义

GC操作基本上只有常量池的回收和类型卸载

运行时常量池

在Class文件中保存的字面量以及符号引用和符号引用解释之后的直接引用放在这里。

运行时常量可以动态的进行添加,典型的用法是String的intern方法,能够看常量池中是否存在,存在则返回这个常量的引用,不存在则创建一个。

2. 各种内存溢出

2.1 堆溢出

设置JVM对内存为比较小。

然后不停的new对象。

-Xms10m -Xmx10m
public class HeapOom {
	public static void main(String[] args) {
		List<OomObject> ooms = new ArrayList<OomObject>();
		while (true) {
			ooms.add(new OomObject());
		}
	}
}

class OomObject{}

输出:

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space

2.2 Java虚拟机站溢出

-Xss 设置每个线程的堆栈大小,越大则能够支持越多层的方法调用。

深度超出的可以使用-Xss设置较小的值,然后使用无跳出方法递归调用来做到

public class StackSOF {
	private int stackLength = 1;
	public void stackLeak(){
		stackLength ++;
		stackLeak();
	}

	public static void main(String[] args) {
		StackSOF ss = new StackSOF();
		try {
			ss.stackLeak();
		} catch (Throwable t) {
			System.out.println("栈深度为:" + ss.stackLength);
			t.printStackTrace();
		}
	}
}

输出:

栈深度为:913
java.lang.StackOverflowError

无法申请到足够的空间,可以用-Xss加到每个线程的栈帧大小。 然后创建多个线程,直到内存溢出。

public class StackOOM {
	public static void main(String[] args) {
		while (true) {
			Thread thread = new Thread(new Runnable() {

				@Override
				public void run() {
					while(true){}
				}
			});

			thread.start();
		}
	}
}

因为Java的线程会映射到Windows内存线程上,因此有可能造成系统假死。另外把-Xss设置的越大,就越会溢出,因为系统物理内存减去JVM的内存再除以Xss才是能创建的线程个数。

2.3 运行时常量溢出

使用-XX:PermSize和-XX:MaxPermSize限制方法区大小

参数

-XX:PermSize=1m -XX:MaxPermSize=2m

代码

public class RuntimeConstPoolOOM {
	public static void main(String[] args) {
		List<String> list = new ArrayList<String>();
		int i = 0;
		while (true) {
			list.add(String.valueOf(i++).intern());
		}
	}
}

输出

Exception in thread "main" java.lang.OutOfMemoryError: PermGen space

2.4 方法区溢出,  加载很多类,或者是使用动态字节码技术等

时间: 2024-08-01 20:14:27

JVM深入学习笔记三:JVM 内存模型的相关文章

JVM深入学习笔记六-JVM类加载

类加载过程 主要分为了 加载->链接(验证->准备->解析)->初始化->使用->卸载这几个阶段. 加载 三件事 1. 通过类的权限定名称来获取定义此类的二进制字节流(可以是文件,网络,数据库,动态等等等等) 2. 把类的结构放在方法区中 3. 创建Class对象作为访问入口 验证 主要包括了字节码验证,元数据验证(这部分在编译期间基本上避免了),类文件格式验证. 准备 包括了内存分配和类变量(static)初始值的设定,以及常量池的写入. 解析 主要是解析符号引用和直

JVM深入学习笔记七-JVM执行

运行时栈帧 栈帧( 局部变量表(基本数据类型,对象引用,returnAddress类型 ), 操作数栈 , 动态链接 , 方法返回地址 ) 局部变量表 以Slot为最小的单位.用来存放32位以内的数据类型.像long,double需要连续的两个Slot 局部变量从0位开始会每一个index对应一个变量的值0一般是this Slot可以改变,当程序计数器指针超出Slot的作用域(用{}指定)的时候则这个Slot就能够复制给其他人了. 垃圾回收的时候Slot会影响GC的行为,比如: public c

kvm虚拟化学习笔记(三)之windows kvm虚拟机安装

原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任.http://koumm.blog.51cto.com/703525/1290191 KVM虚拟化学习笔记系列文章列表 ---------------------------------------- kvm虚拟化学习笔记(一)之kvm虚拟化环境安装http://koumm.blog.51cto.com/703525/1288795 kvm虚拟化学习笔记(二)之linux kvm虚拟机安装 h

VSTO学习笔记(三) 开发Office 2010 64位COM加载项

原文:VSTO学习笔记(三) 开发Office 2010 64位COM加载项 一.加载项简介 Office提供了多种用于扩展Office应用程序功能的模式,常见的有: 1.Office 自动化程序(Automation Executables) 2.Office加载项(COM or Excel Add-In) 3.Office文档代码或模板(Code Behind an Office Document or Template) 4.Office 智能标签(Smart Tags) 本次我们将学习使

Bootstrap3学习笔记(三)之表格_javascript技巧

在上篇文章给大家介绍了 BootStrap3学习笔记(一)之网格系统       Bootstrap3学习笔记(二)之排版 只需要在table标签上使用.table类,就可以使用bootstrap默认的表格样式 如果需要行背景有交替变化,可以这样设定: 复制代码 代码如下: <table class="table table-striped"> 如果需要边框,可以这样设定: 复制代码 代码如下: <table class="table table-borde

JavaScript学习笔记(三):JavaScript也有入口Main函数_javascript技巧

在C和Java中,都有一个程序的入口函数或方法,即main函数或main方法.而在JavaScript中,程序是从JS源文件的头部开始运行的.但是某种意义上,我们仍然可以虚构出一个main函数来作为程序的起点,这样一来不仅可以跟其他语言统一了,而且说不定你会对JS有更深的理解. 1. 实际的入口 当把一个JavaScript文件交给JS引擎执行时,JS引擎就是从上到下逐条执行每条语句的,直到执行完所有代码. 2. 作用域链.全局作用域和全局对象 我们知道,JS中的每个函数在执行时都会产生一个新的

DB2 UDB V8.1管理学习笔记(三)_DB2

正在看的db2教程是:DB2 UDB V8.1管理学习笔记(三).强制断开已有连接,停止实例并删除.  $ db2idrop -f instance_name 用于在UNIX下迁移实例. $ db2imigr instance_name 更新实例,用于实例获得一些新的产品选项或修订包的访问权. $ db2iupdt instance_name 获取当前所处的实例. $ db2 get instance 当更新实例级别或数据库级别的参数后,有些可以立即生效,有些需要重新启动实例才可生效.immed

实现按行读取文件,把内容按照第三种内存模型打包数据传出,把行数通过函数参数传出。

/* 2 编写一个业务函数,实现按行读取文件.把内容按照第三种内存模型打包数据传出,把行数通过函数参数传出. 函数原型有两个,任意选择其一 要求1:请自己任意选择一个接口(函数),并实现功能:70分 要求2:编写测试用例.30分 要求3:自己编写内存释放函数 */ /********************************************************************** * 版权所有 (C)2015, Wu Yingqiang. * * 文件名称:ReadFi

Java笔记:Java内存模型

1. 基本概念 <深入理解Java内存模型>详细讲解了java的内存模型,这里对其中的一些基本概念做个简单的笔记.以下内容摘自 <深入理解Java内存模型>读书总结 并发 定义:即,并发(同时)发生.在操作系统中,是指一个时间段中有几个程序都处于已启动运行到运行完毕之间,且这几个程序都是在同一个处理机上运行,但任一个时刻点上只有一个程序在处理机上运行. 并发需要处理两个关键问题:线程之间如何通信及线程之间如何同步. 通信:是指线程之间如何交换信息.在命令式编程中,线程之间的通信机制