Java虚拟机

JVM内存模型:

线程私有的运行时数据区: 程序计数器、Java 虚拟机栈、本地方法栈。

线程共享的运行时数据区:Java 堆、方法区。

 

(1)程序计数器:

程序计数器表示当前线程所执行的字节码的行号指示器。

程序计数器不会产生StackOverflowError和OutOfMemoryError。

(2)虚拟机栈:

Java 虚拟机栈用来描述 Java 方法执行的内存模型。线程创建时就会分配一个栈空间,线程结束后栈空间被回收。

栈中元素用于支持虚拟机进行方法调用,每个方法在执行时都会创建一个栈帧存储方法的局部变量表、操作栈、动态链接和返回地址等信息。

虚拟机栈会产生两类异常:

StackOverflowError:线程请求的栈深度大于虚拟机允许的深度抛出。

OutOfMemoryError:如果 JVM 栈容量可以动态扩展,虚拟机栈占用内存超出抛出。

(3)本地方法栈:

本地方法栈与虚拟机栈作用相似,不同的是虚拟机栈为虚拟机执行 Java 方法服务,本地方法栈为本地方法服务。可以将虚拟机栈看作普通的java函数对应的内存模型,本地方法栈看作由native关键词修饰的函数对应的内存模型。

本地方法栈会产生两类异常:

StackOverflowError:线程请求的栈深度大于虚拟机允许的深度抛出。

OutOfMemoryError:如果 JVM 栈容量可以动态扩展,虚拟机栈占用内存超出抛出。

(4)JVM中的堆:

堆主要作用是存放对象实例,Java 里几乎所有对象实例都在堆分配内存,堆也是内存管理中最大的一块。Java的垃圾回收主要就是针对堆这一区域进行。可通过 -Xms 和 -Xmx 设置堆的最小和最大容量。

堆会抛出 OutOfMemoryError异常。

(5)方法区:

方法区用于存储被虚拟机加载的类信息、常量、静态变量等数据。

JDK6之前使用永久代实现方法区,容易内存溢出。JDK7 把放在永久代的字符串常量池、静态变量等移出,JDK8 中抛弃永久代,改用在本地内存中实现的元空间来实现方法区,把 JDK 7 中永久代内容移到元空间。

方法区会抛出 OutOfMemoryError异常。

(6)运行时常量池:

运行时常量池存放常量池表,用于存放编译器生成的各种字面量与符号引用。一般除了保存 Class 文件中描述的符号引用外,还会把符号引用翻译的直接引用也存储在运行时常量池。除此之外,也会存放字符串基本类型。

JDK8之前,放在方法区,大小受限于方法区。JDK8将运行时常量池存放堆中。

(7)直接内存:

直接内存也称为堆外内存,就是把内存对象分配在JVM堆外的内存区域。这部分内存不是虚拟机管理,而是由操作系统来管理。Java通过通过DriectByteBuffer对其进行操作,避免了在 Java 堆和 Native堆来回复制数据。

(8)java创建对象的过程:

1、检查该指令的参数能否在常量池中定位到一个类的符号引用,并检查引用代表的类是否已被加载、解析和初始化,如果没有就先执行类加载

2、通过检查通过后虚拟机将为新生对象分配内存。

原文地址:https://www.cnblogs.com/KL2016/p/15268964.html