前一段时间粗略看了一下《深刻Java虚拟机 第二版》,多是由于工做才一年的缘由吧,看着十分的吃力。毕竟若是具体到细节的话,Java虚拟机涉及的内容太多了。可能再过一两年去看会合适一些吧。前端
不过看了一遍《深刻Java虚拟机》再来理解Java内存管理会好不少。接下来一块儿学习下Java内存管理吧。数据结构
请注意上图的这个:框架
进程是具备必定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的一个独立单位。学习
线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。线程本身基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),可是它可与同属一个进程的其余的线程共享进程所拥有的所有资源。.net
彷佛如今更好理解了一些:线程
方法区和堆是分配给进程的,也就是全部线程共享的。3d
而栈和程序计数器,则是分配给每一个独立线程的,是运行过程当中必不可少的资源。对象
方法区(Method Area)与Java堆同样,是各个线程共享的内存区域,它用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。虽然Java虚拟机规范把方法区描述为堆的一个逻辑部分,可是它却有一个别名叫作Non-Heap(非堆),目的应该是与Java堆区分开来。blog
程序计数器(Program Counter Register)是一块较小的内存空间,它的做用能够看作是当前线程所执行的字节码的行号指示器。在虚拟机的概念模型里(仅是概念模型,各类虚拟机可能会经过一些更高效的方式去实现),字节码解释器工做时就是经过改变这个计数器的值来选取下一条须要执行的字节码指令,分支、循环、跳转、异常处理、线程恢复等基础功能都须要依赖这个计数器来完成。进程
下面重点解下Java内存管理中的栈和堆。
在Java中,JVM中的栈记录了线程的方法调用。每一个线程拥有一个栈。在某个线程的运行过程当中,若是有新的方法调用,那么该线程对应的栈就会增长一个存储单元,即帧(frame)。在frame中,保存有该方法调用的参数、局部变量和返回地址。
Java的参数和局部变量只能是基本类型的变量(好比int),或者对象的引用(reference)。所以,在栈中,只保存有基本类型的变量和对象引用。引用所指向的对象保存在堆中。(引用可能为Null值,即不指向任何对象)。
当被调用方法运行结束时,该方法对应的帧将被删除,参数和局部变量所占据的空间也随之释放。线程回到原方法,继续执行。当全部的栈都清空时,程序也随之运行结束。
本地方法栈(Native Method Stacks)与虚拟机栈所发挥的做用是很是类似的,其区别不过是虚拟机栈为虚拟机执行Java方法(也就是字节码)服务,而本地方法栈则是为虚拟机使用到的Native方法服务。虚拟机规范中对本地方法栈中的方法使用的语言、使用方式与数据结构并无强制规定,所以具体的虚拟机能够自由实现它。甚至有的虚拟机(譬如Sun HotSpot虚拟机)直接就把本地方法栈和虚拟机栈合二为一。与虚拟机栈同样,本地方法栈区域也会抛出StackOverflowError和OutOfMemoryError异常。
##四、堆(Heap)
堆是JVM中一块可自由分配给对象的区域。当咱们谈论垃圾回收(garbage collection)时,咱们主要回收堆(heap)的空间。
Java的普通对象存活在堆中。与栈不一样,堆的空间不会随着方法调用结束而清空。所以,在某个方法中建立的对象,能够在方法调用结束以后,继续存在于堆中。这带来的一个问题是,若是咱们不断的建立新的对象,内存空间将最终消耗殆尽。