java虚拟机之-内存区域

来源:互联网 发布:程序员属于什么行业 编辑:程序博客网 时间:2024/06/06 08:37

内存区域
Java虚拟机在执行Java程序的过程中会把他所管理的内存划分为若干个不同的数据区域。Java虚拟机规范将JVM所管理的内存分为以下几个运行时数据区:程序计数器、Java虚拟机栈、本地方法栈、Java堆、方法区。下面详细阐述各数据区所存储的数据类型。

这里写图片描述

程序计数器(Program Counter Register)

运行时数据区域-程序计数器

一块较小的内存空间,它是当前线程所执行的字节码的行号指示器,字节码解释器工作时通过改变该计数器的值来选择下一条需要执行的字节码指令,分支、跳转、循环等基础功能都要依赖它来实现。每条线程都有一个独立的的程序计数器,各线程间的计数器互不影响,因此该区域是线程私有的。

当线程在执行一个Java方法时,该计数器记录的是正在执行的虚拟机字节码指令的地址,当线程在执行的是Native方法(调用本地操作系统方法)时,该计数器的值为空。另外,该内存区域是唯一一个在Java虚拟机规范中么有规定任何OOM(内存溢出:OutOfMemoryError)情况的区域。

总结:程序计数器可以看作是当前线程所执行的字节码的行号子令器,大白话就是一个计算行号的计算器;程序中的分支、循环、跳转、异常处理、线程恢复等基础功能都需要依赖这个计数器来完成。

计数器相关文章:
https://my.oschina.net/sld880311/blog/1485929
http://blog.csdn.net/liushanwu635/article/details/50903257
https://www.zhihu.com/question/49597071

虚拟机栈

JVM栈解决程序的运行问题,即程序如何执行,或者说如何处理数据;JVM堆解决的是数据存储的问题,即数据怎么放、放在哪儿,另外JVM堆中存的是对象。JVM栈中存的是基本数据类型和JVM堆中对象的引用。
Java虚拟机中,数据类型可以分为两类:基本类型和引用类型。基本类型的变量保存原始值,即:他代表的值就是数值本身;而引用类型的变量保存引用值。“引用值”代表了某个对象的引用,而不是对象本身,对象本身存放在这个引用值所表示的地址的位置。
基本类型包括:byte,short,int,long,char,float,double,Boolean,returnAddress
引用类型包括:类类型,接口类型和数组。
JVM栈是运行时的单位,而JVM堆是存储的单位。

JVM堆中存的是对象。JVM栈中存的是基本数据类型和JVM堆中对象的引用。一个对象的大小是不可估计的,或者说是可以动态变化的,但是在JVM栈中,一个对象只对应了一个4btye的引用(JVM堆JVM栈分离的好处:))。

虚拟机栈描述的是Java方法执行的内存模型,属于线程私有,其声明周期与线程相同。每个方法执行的时候都会同时创建一个栈帧,用户存储变量表,操作栈,动态链接,方法出口等信息,每个方法调用直至执行完成的过程就对应着一个栈帧入栈到出栈的过程。我们通常所说的栈指的就是虚拟机栈中的局部变量表。局部变量表存储了编译器可知的基本数据类型(boolean,short,char,int,float,long,double)、对象引用、returnAddress类型。局部变量表所需的空间在编译期中就已经确定。

为什么不把基本类型放JVM堆中呢?因为其占用的空间一般是1~8个字节——需要空间比较少,而且因为是基本类型,所以不会出现动态增长的情况——长度固定,因此JVM栈中存储就够了,如果把他存在JVM堆中是没有什么意义的(还会浪费空间,后面说明)。可以这么说,基本类型和对象的引用都是存放在JVM栈中,而且都是几个字节的一个数,因此在程序运行时,他们的处理方式是统一的。但是基本类型、对象引用和对象本身就有所区别了,因为一个是JVM栈中的数据一个是JVM堆中的数据。最常见的一个问题就是,Java中参数传递时的问题。

堆栈资料:
http://developer.51cto.com/art/201009/227812_all.htm
https://github.com/dodola/dodo_algorithm/blob/master/java/jvm/jvmdui_zhan.md
http://blog.csdn.net/ns_code/article/details/17565503

本地方法栈

本地方法栈和虚拟机栈发挥的作用是相似的。不同点在于,本地方法栈是为虚拟机执行的native方法服务;虚拟机栈是为虚拟机执行java方法而服务,

本地方法栈资料:
https://my.oschina.net/wangsifangyuan/blog/669331
http://www.cnblogs.com/wade-luffy/p/5813747.html

java堆

Java 堆包含 Java 对象实例,通常称为“堆”。它是由垃圾回收进行维护且可通过命令行堆设置进行更改的 Java 堆。如果请求了大页面支持,将使用 mmap 或 shmat 来分配 Java 堆。在 JVM 启动过程中,将预分配 Java 堆的最大大小作为一个连续区域,即使最小堆大小设置较低也如此。 此分配允许通过堆扩展,将最小堆大小设置施加的人为堆大小限制移至实际堆大小限制。

堆和栈的区别:
功能不同
栈内存用来存储局部变量和方法调用。
而堆内存用来存储Java中的对象。无论是成员变量,局部变量,还是类变量,它们指向的对象都存储在堆内存中。
共享性不同
栈内存是线程私有的。
堆内存是所有线程共有的。
异常错误不同
如果栈内存或者堆内存不足都会抛出异常。
栈空间不足:java.lang.StackOverFlowError。
堆空间不足:java.lang.OutOfMemoryError。
空间大小
栈的空间大小远远小于堆的。

堆资料:
https://iamjohnnyzhuang.github.io/java/2016/07/12/Java%E5%A0%86%E5%92%8C%E6%A0%88%E7%9C%8B%E8%BF%99%E7%AF%87%E5%B0%B1%E5%A4%9F.html
https://www.ibm.com/support/knowledgecenter/zh/SSYKE2_7.0.0/com.ibm.java.aix.70.doc/diag/problem_determination/aix_mem_heaps.html

方法区

方法区在什么时候用到:
当JVM使用类装载器装载某个类时,它首先要定位对应的class文件,然后读入这个class文件,最后,JVM提取该文件的内容信息,并将这些信息存储到方法区,最后返回一个class实例。

方法区以及其特点
方法区是系统分配的一个内存逻辑区域,是用来存储类型信息的(类型信息可理解为类的描述信息)。方法区主要有以下几个特点:
一.方法区是线程安全的。由于所有的线程都共享方法区,所以,方法区里的数据访问必须被设计成线程安全的。例如,假如同时有两个线程都企图访问方法区中的同一个类,而这个类还没有被装入JVM,那么只允许一个线程去装载它,而其它线程必须等待
二.方法区的大小不必是固定的,JVM可根据应用需要动态调整。同时,方法区也不一定是连续的,方法区可以在一个堆(甚至是JVM自己的堆)中自由分配。
三.方法区也可被垃圾收集,当某个类不在被使用(不可触及)时,JVM将卸载这个类,进行垃圾收集

资料:
http://www.jianshu.com/p/10584345b10a
http://xtu-tja-163-com.iteye.com/blog/769992