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

简介: <p>1. JVM运行时内存 图</p> <p><img src="http://img.blog.csdn.net/20141002191517107?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdGhyZWVfbWFu/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gra

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 方法区溢出,  加载很多类,或者是使用动态字节码技术等


相关文章
|
2月前
|
存储 设计模式 监控
快速定位并优化CPU 与 JVM 内存性能瓶颈
本文介绍了 Java 应用常见的 CPU & JVM 内存热点原因及优化思路。
608 166
|
4月前
|
缓存 Prometheus 监控
Elasticsearch集群JVM调优设置合适的堆内存大小
Elasticsearch集群JVM调优设置合适的堆内存大小
713 1
|
1天前
|
存储 设计模式 监控
如何快速定位并优化CPU 与 JVM 内存性能瓶颈?
如何快速定位并优化CPU 与 JVM 内存性能瓶颈?
|
11天前
|
存储 算法 Java
JVM: 内存、类与垃圾
分代收集算法将内存分为新生代和老年代,分别使用不同的垃圾回收算法。新生代对象使用复制算法,老年代对象使用标记-清除或标记-整理算法。
18 3
|
3月前
|
存储 Java 程序员
【JVM】——JVM运行机制、类加载机制、内存划分
JVM运行机制,堆栈,程序计数器,元数据区,JVM加载机制,双亲委派模型
|
3月前
|
存储 监控 算法
深入探索Java虚拟机(JVM)的内存管理机制
本文旨在为读者提供对Java虚拟机(JVM)内存管理机制的深入理解。通过详细解析JVM的内存结构、垃圾回收算法以及性能优化策略,本文不仅揭示了Java程序高效运行背后的原理,还为开发者提供了优化应用程序性能的实用技巧。不同于常规摘要仅概述文章大意,本文摘要将简要介绍JVM内存管理的关键点,为读者提供一个清晰的学习路线图。
|
4月前
|
Java
JVM内存参数
-Xmx[]:堆空间最大内存 -Xms[]:堆空间最小内存,一般设置成跟堆空间最大内存一样的 -Xmn[]:新生代的最大内存 -xx[use 垃圾回收器名称]:指定垃圾回收器 -xss:设置单个线程栈大小 一般设堆空间为最大可用物理地址的百分之80
|
4月前
|
Java
JVM运行时数据区(内存结构)
1)虚拟机栈:每次调用方法都会在虚拟机栈中产生一个栈帧,每个栈帧中都有方法的参数、局部变量、方法出口等信息,方法执行完毕后释放栈帧 (2)本地方法栈:为native修饰的本地方法提供的空间,在HotSpot中与虚拟机合二为一 (3)程序计数器:保存指令执行的地址,方便线程切回后能继续执行代码
40 3
|
4月前
|
存储 缓存 监控
Elasticsearch集群JVM调优堆外内存
Elasticsearch集群JVM调优堆外内存
77 1
|
4月前
|
Arthas 监控 Java
JVM进阶调优系列(9)大厂面试官:内存溢出几种?能否现场演示一下?| 面试就那点事
本文介绍了JVM内存溢出(OOM)的四种类型:堆内存、栈内存、元数据区和直接内存溢出。每种类型通过示例代码演示了如何触发OOM,并分析了其原因。文章还提供了如何使用JVM命令工具(如jmap、jhat、GCeasy、Arthas等)分析和定位内存溢出问题的方法。最后,强调了合理设置JVM参数和及时回收内存的重要性。