Java程序在运行时,须要在内存中分配空间。为了提升运行效率,就对数据进行了不一样的空间划分。由于每一片区域都有特定的数据处理方式和内存管理方式。html
具体分为5种内存空间:java
程序计数器:保证线程切换后能恢复到原来的执行位置。算法
虚拟机栈:(栈内存)为虚拟机执行java方法服务,方法被调用时,建立栈帧-数据结构
本地方法栈:为虚拟机执行使用到的Native方法服务多线程
堆内存:存放全部new出来的东西post
方法区:存储被虚拟机加载的类信息,常量,静态常量,静态方法等。url
运行时常量池(方法区的一部分).net
GC对他们的回收:线程
内存区域中的程序计数器、虚拟机栈、本地方法栈这3个区域随着线程而生,线程而灭;栈中的栈帧随着方法的进入和退出而有条件的执行出栈和入栈的操做。每一个栈帧中分配多少内存基本是在类结构肯定下来时就已知的。在这个区域不须要过多的考虑回收的问题,由于方法结束或者线程结束时,内存天然就跟着回收了。3d
GC回收的主要对象:Java堆和方法区
一个接口中的多个实现类须要的内存可能不一样,一个方法中的多个分支须要的内存也可能不同,咱们只有在程序处于运行期间时才能知道会建立哪些对象,这部份内存的分配和回收都是动态的,GC关注的也是这部份内存。
1.程序计数器:(线程私有)
每隔线程拥有一个程序计数器,在线程建立时建立,指向吓一跳指令的地址
执行本地方法时,其值为undefined。
说的通俗一点,咱们知道,Java是支持多线程的,程序先去执行A线程,执行到一半而后去执行B线程,而后又跑去接着执行A线程,那程序是怎么记住A线程已经执行到哪里了呢?这就须要程序计数器了。所以,为了线程切换后可以恢复到正确执行的位置,每条线程都有一个独立的程序计数器,这块属于“线程私有”的内存。
2.Java虚拟机栈(线程私有)
每隔方法被调用的时候会建立一个栈帧,用于存储局部变量表,操做栈,动态连接,方法出口等信息。局部变量表存放的是:编译器可知的基本数据类型,对象引用类型。
每一个方法被调用直到执行完的过程,就对应着一个栈帧在虚拟机中从引入到出栈的过程。
在Java虚拟机中,对这个区域规定了两种异常状况:
(1)若是线程请求的栈深度太深,超出了虚拟机所容许的深度,就会出现StackOverFlowError(好比无线递归,由于每一层栈帧都会占用必定空间,erXss规定了栈的最大空间,超出这个值就会报错)
(2)虚拟机栈能够动态扩展,若是扩展到没法申请足够的内存空间,会出现OOM(OutOfMemory)
3.本地方法栈:
(1)本地方法栈与java虚拟机栈作用户很是类似,区别是:java虚拟机栈是为虚拟机执行java方法服务的而本地方法栈则是为虚拟机使用到Native方法服务。
(2)Java虚拟机没有对本地方法栈的使用和数据结构作强制规定,Sun HotSpot虚拟机就把java虚拟机栈和本地方法栈合二为一。
(3)本地方法栈也会抛出StackOverFlowError和OutOfMemoryError
4.Java堆:堆内存
(1)堆是Java虚拟机所管理的内存区域中罪的的一块,java堆是被全部县城共享的内存区域,在java虚拟机启动时建立堆内存的惟一目的就是存放对象实例,几乎全部的对象实例都在堆内存分配。
(2)堆是GC管理的主要区域,从垃圾回收的角度看,因为如今的垃圾收集器都是采用的粉黛手机算法,所以java堆还能够初步细分为新生代和老年代。
(3)Java虚拟机规定,堆能够处于物理上不连续的内存空间中,只要逻辑上连续的便可。在实现的既能够是固定的,也能够是动态扩展的。若是在堆内存没有完成实力分配,而且对大小也没法扩展,就会抛出OutOfMemoryError异常。
5.方法区(线程共享)
(1)用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码数据。
(2)Sun HotSpot虚拟机把方法区叫作永久带(permanent Generation),方法区中最终要的部分是运行时常量池。
6.运行时常量池:
(1)运行时常量池是方法区的一部分,天然受到方法区内存的限制,当常量池没法再申请到内存时就会抛出OutOfMemoryError异常。
参考:
1.java虚拟机详解:http://www.cnblogs.com/smyhvae/p/4748392.html
2.java中的各类数据类型在内存中存储的方式:https://blog.csdn.net/sinat_29255093/article/details/52556449