Java 内存管理机制,深入理解JVM
概述:在JVM的自动内存管理机制的支持下,不需要为每一个new的对象进行delete/free。本文将讨论在内存溢出和溢出方面的问题以及数据存放区域。
常见异常:
StackOverFloeError(线程请求栈的深度大于JVM允许的Max Value)
OutOfMemoryError(动态扩展是大于JVM允许的Max Value,注意,这个时候是在扩展,上一个错误是在请求)。
一:数据存放区域。
1.方法区:method Area
这个区域线程共享。存放类加载信息,常量,静态变量,JIT编译后的代码。
里面有运行时常量池,包含符号引用等。
这个区域会出:OutOfMemoryError
2.虚拟机栈 :VM Stack
这个区域是线程私有的。
当方法被执行的时候,这个时候在该区域会创建一个Stack Frame存储局部变量表,操作栈,动态链接,方法出口等信息。一个方法的执行也就意味着一个栈帧在VM Stack里面从入栈到出栈的过程。
这个区域我们着重考虑局部变量表,里面存放了各种的数据类型,只有64位的long和double占用2个局部变量空间,其他的都是一个。
异常:StackOverFloeError,OutOfMemoryError.
3.本地方法栈:Native Method Stack
与虚拟机栈相似,只是他是为Native方法服务,但是虚拟机栈为Java方法(也就是字节码)提供服务。
4.程序计数器:Program Couter Register
该区域较小,可以看做是当前线程的字节码行号指示器,用来选择下一条需要执行的语句。
线程管理:由于线程切换需要恢复到正常的执行的位置,所以一个线程就需要一个程序计数器(线程私有)。
5.堆:Heap
这个区域线程共享。在JVM创建的时候就创建了。对象实例,数组都在这里进行分配。
Java的垃圾回收区域也存放在这个区域(Garbage Collected Heap,采用分代收集算法,详情百度)。
这个区域也会出这个错误:OutOfMemoryError
6.直接内存:Direct Memory
这个区域独立于堆,可以直接使用Native函数分配堆外内存。
每个区域都有创建和销毁的时间,都有各自的用途。
一个面试题:解释内存中的栈(stack)、堆(heap)和方法区(method area)的用法。
答:通常我们定义一个基本数据类型的变量,一个对象的引用,还有就是函数调用的现场保存都使用JVM中的栈空间;而通过new关键字和构造器创建的对象则放在堆空间,堆是垃圾收集器管理的主要区域,由于现在的垃圾收集器都采用分代收集算法,所以堆空间还可以细分为新生代和老生代,再具体一点可以分为Eden、Survivor(又可分为From Survivor和To Survivor)、Tenured;方法区和堆都是各个线程共享的内存区域,用于存储已经被JVM加载的类信息、常量、静态变量、JIT编译器编译后的代码等数据;程序中的字面量(literal)如直接书写的100、”hello”和常量都是放在常量池中,常量池是方法区的一部分,。栈空间操作起来最快但是栈很小,通常大量的对象都是放在堆空间,栈和堆的大小都可以通过JVM的启动参数来进行调整,栈空间用光了会引发*Error,而堆和常量池空间不足则会引发OutOfMemoryError。
二:对象访问。
Object obj = new Object(); // Object obj放在本地变量中,new的对象放在堆里面。
访问方式 | 句柄访问 | 直接访问 |
---|---|---|
好处 | 地址稳定,对象被移动时改变的只是实例化的数据指针,reference本身不修改 | 速度很快 |
三:常见的错误产生
OutOfMemoryError
模拟条件:while死循环创建对象,导致Heap溢出,产生OutOfMemoryError
*
创建大量变量(虚拟栈)
上一篇: 深入理解JVM(三)--对象存活判定算法
下一篇: c++和Java数组内存空间申请