java虚拟机在执行java程序的过程中,会把内存划分为若干个不同的数据区域。每个区域都有各自的用途,创建和销毁时间,按照《java虚拟机规范(Java SE 7 版)》的规定,虚拟机运行时数据区域主要有以下几种:

1.程序计数器

  程序计数器是很小的一块内存区域,可以看做是当前线程所执行字节码的行号指示器。在虚拟机的概念模型中,字节码解释器工作时就是通过改变程序计数器的值来选取下一条需要执行的字节码指令,分支,循环,跳转,异常处理,线程恢复等基础功能均依赖于程序计数器。在多线程中,每个线程都有一个独立的程序计数器,每个线程的程序计数器之间互不影响,即“线程私有”。同时,程序计数器是java虚拟机规范中唯一一个没有规定OutOfMemoryError的区域。

2.java虚拟机栈

  虚拟机栈描述的是java方法执行的内存模型,每个方法在执行时候都会创建一个栈帧用于存储局部变量表,操作数栈,动态链接,方法出口等信息。每个方法从被调用执行到执行完成的过程,就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。虚拟机栈也是线程私有的。在Java虚拟机规范中,虚拟机栈有两种异常状况:

(1)线程请求的栈深度大于虚拟机栈所允许的深度,将抛出StackOverflowError异常;

(2)如果虚拟机栈可以动态扩展,但扩展时无法申请到足够的内存,或者在创建新线程时候没有足够的内存去创建虚拟机栈,就会抛出OutOfMemoryError异常。

3.本地方法栈

  本地方法栈和虚拟机栈的作用类似,区别在于java虚拟机栈支持Java方法执行,而本地方法栈则支持native方法执行。有些虚拟机直接将java虚拟机栈和本地方法栈合二为一,本地方法栈的异常情况与java虚拟机栈的内存一致,即:

(1)线程请求的栈深度大于本地方法栈所允许的深度,将抛出StackOverflowError异常;

(2)如果本地方法栈可以动态扩展,但扩展时无法申请到足够的内存,或者在创建新线程时候没有足够的内存去创建本地方法栈,就会抛出OutOfMemoryError异常。

4.java堆

  java堆是Java虚拟机所管理的内存中最大的一块,它是被所有线程所共享的内存区域,在虚拟机启动时候创建。java堆是供所有类实例和数组分配内存的区域,也是垃圾收集器管理的主要区域,因此很多时候也被称为“GC堆”。从内存回收的角度来看,由于收集器基本都采用分代收集算法,所以Java堆还可以细分为新生代(Young Gen)和老年代(Old Gen)。新生代又可以继续分为Eden空间,From Survivor空间,To Survivor空间。如下图:

  Java堆的大小可以是固定的,也可以是随着程序执行动态扩展,并在不需要过多空间时候自动收缩。且Java堆所使用的内存不需要保证是连续的。如果实际所需的堆超过了自动内存管理系统所能提供的最大容量,java虚拟机将会抛出一个OutOfMemoryError异常。

  Java堆常用调节参数:

   -Xms128M :设置初始堆大小为128M
   -Xmx512M :设置最大堆大小为512M
   -XX:NewSize=n :设置年轻代大小;
   -XX:NewRatio=n :设置年轻代和年老代的比值,如设置为3,表示年轻代与年老代比值为1:3,年轻代占整个年轻代年老代的1/4;
   -XX:SurvivorRatio=n :年轻代中Eden区与两个Survivor区的比值(年轻代分成1个Eden Space和2个Suvivor Space),如设置为3,表示Eden:Survivor=3:2,一个Survivor区占整个年轻代的1/5;

5.方法区

  方法区和java堆一样,是所有线程共享的内存区域。它存储了每一个类的结构信息,例如运行时常量池,字段和方法数据,构造函数和普通方法的字节码内容,还包括一些在类,实例,接口初始化时用到的特殊方法。由于HotSpot虚拟机设计团队将GC分代扩展到了方法区,或者说使用“永久代”来实现方法区,这样HotSpot的垃圾收集器就可以像管理Java堆那样来管理方法区内存,故很多人将方法区称为永久代,但本质上两者不是等价的(Java8中,HotSpot对于方法区的实现从永久代变更为元空间Metaspace)对于其他虚拟机(如BEA JRockit,IBM J9等)而言是不存在永久代的。按照java虚拟机规范,当方法区不能满足内存分配请求时,java虚拟机将抛出OutOfMemoryError异常。

  方法区常用调节参数:

  java8之前(设置永久代):

   -XX:PermSize=64M  :设置持久代初始大小
   -XX:MaxPermSize=128M  :设置持久代最大允许分配大小。

  java8之后(设置元空间):  

   -XX:MetaspaceSize=8M :设置元空间大小为8M
   -XX:MaxMetaspaceSize=80M :设志元空间最大为80M
   -XX:MinMetaspaceFreeRatio=n :当进行过Metaspace GC之后,会计算当前Metaspace的空闲空间比,如果空闲比小于这个参数,那么虚拟机将增长Metaspace的大小。默认值为40,也就是40%
   -XX:MaxMetasaceFreeRatio=n :当进行过Metaspace GC之后, 会计算当前Metaspace的空闲空间比,如果空闲比大于这个参数,那么虚拟机会释放Metaspace的部分空间。默认值为70,也就是70%
   -XX:MaxMetaspaceExpansion=n :设置Metaspace增长时的最大幅度
   -XX:MinMetaspaceExpansion=n :设置Metaspace增长时的最小幅度

6.运行时常量池

  运行时常量池是方法区的一部分,是class文件中每一个类或者接口的常量池表在运行时的表现形式。在加载类和接口到虚拟机后,就创建对应的运行时常量池。如果构造运行时常量池所需要的内存空间超过了方法区所能提供的最大值,Java虚拟机就会抛出一个OutOfMemoryError异常。

  需要特别注意的是,运行时常量池和字符串常量池的区别,在jdk1.7之前,运行时常量池逻辑包含字符串常量池存放在方法区,此时hotspot虚拟机对方法区的实现为永久代。在JDK1.7 字符串常量池被从方法区拿到了堆中,运行时常量池剩下的东西还在方法区, 也就是hotspot中的永久代。JDK1.8 hotspot移除了永久代引入元空间(Metaspace), 这时候字符串常量池还在堆中, 运行时常量池还在方法区, 只不过方法区的实现从永久代变成了元空间(Metaspace)。

参考资料:

《深入理解Java虚拟机 JVM高级特性与最佳实践 第2版》

《Java虚拟机规范(Java SE 7)》

Java虚拟机一:运行时数据区域的更多相关文章

  1. 深入理解Java虚拟机-JVM运行时数据区域

    一.运行时数据区域 1.程序计数器 程序计数器( Program Counter Register) 是一块较小的内存空间, 它可以看作是当前线程所执行的字节码的行号指示器. Java虚拟机的多线程是 ...

  2. Java虚拟机及运行时数据区

    1.Java虚拟机的定义 Java虚拟机(Java Virtual Machine),简称JVM.当我们说起Java虚拟机时,可能指的是如下三种不同的东西: 抽象的虚拟机规范 规范的具体实现 一个运行 ...

  3. Java虚拟机_运行时数据区

    Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干个不同的数据区域. 这些区域都有各自的用途.各自的创建和销毁的时间,有的区域随着虚拟机进程的启动而存在,有些区域则是依赖用户线程启动 ...

  4. 【Java虚拟机】运行时数据区

    Java在执行Java程序的过程中会把它所管理的内存划分为若干个不同的数据区域.这些区域都有各自的用途.创建和销毁的时间,有一些是随虚拟机的启动而创建,随虚拟机的退出而销毁,有些则是与线程一一对应,随 ...

  5. 想买保时捷的运维李先生学Java性能之 运行时数据区域

    前言 不知道自己不知道,不知道自己知道,知道自己不知道,知道自己知道,目前处于知道自己不知道这个阶段,很痛苦啊,干了4年了运维,是一个坎.越来越发觉想要走得远,还是得扎根底.   一.运行时数据区域 ...

  6. Java虚拟机一 运行时数据区(栈、堆、方法区等)

    Java虚拟机的内存管理主要分两点:内存分配以及内存回收.· 一.内存分配图: 注: 所占区域的大小与实际的内存大小比例并无直接关系. 解读: 1.如图,分成两种颜色的内存区域,其中蓝色的是线程隔离的 ...

  7. 深入理解Java虚拟机(一) 运行时数据区划分

    前言:从我学Java的第一天开始,我的大学老师就告诉我 Java语言相比C.C++的语言有一个非常强大的功能,那就是自动内存管理:我们用Java编码时不需要申请或释放内存等,这些工作全部交由我们的Ja ...

  8. java虚拟机规范-运行时数据区

    前言 java虚拟机是java跨平台的基石,本文的描述以jdk7.0为准,其他版本可能会有一些微调. 引用 java虚拟机规范 数据类型 java总共有两种数据类型:基本类型和引用类型.java虚拟机 ...

  9. java虚拟机规范-运行时栈帧

    前言 java虚拟机是java跨平台的基石,本文的描述以jdk7.0为准,其他版本可能会有一些微调. 引用 java虚拟机规范 java虚拟机规范-运行时数据区 java内存运行时的栈帧结构 java ...

  10. Java虚拟机-运行时数据区域

    Java虚拟机管理的内存包括如图所示的运行时数据区域: 下面分别进行介绍: 1)程序计数器(Program Counter Register) 占用的内存空间比较小,主要作用就是标识当前线程执行的字节 ...

随机推荐

  1. 高性能网络通信框架 HP-Socket

      HP-Socket 详细介绍 HP-Socket 是一套通用的高性能 TCP/UDP/HTTP 通信框架,包含服务端组件.客户端组件和Agent组件,广泛适用于各种不同应用场景的 TCP/UDP/ ...

  2. hdu-3071 Gcd & Lcm game---质因数分解+状态压缩+线段树

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=3071 题目大意: 给定一个长度为n的序列m次操作,操作的种类一共有三种 查询 L :查询一个区间的所 ...

  3. PHP内核之旅-3.变量

    PHP 内核之旅系列 PHP内核之旅-1.生命周期 PHP内核之旅-2.SAPI中的Cli PHP内核之旅-3.变量 一.弱类型语言 php是弱类型语言.一个变量可以表示任意数据类型. php强大的一 ...

  4. mysql explain中key_len值的说明

    在mysql 的explain的输出中,有个key_len的列,其数据是如何计算的呢? 在看到了淘宝的dba以前发布的博客后,我在mysql 5.6上操作一番,了解了一点. 环境准备 – 创建表. u ...

  5. LoadRunner性能测试工具

    1:LoadRunner是一款性能测试软件,通过模拟真实的用户行为,通过负载.并发和性能实时监控以及完成后的测试报告,分析系统可能存在的瓶颈,LoadRunner最为有效的手段之一应该就是并发的控制. ...

  6. .net如何使用系统中没有安装的字体?

    不想安装到客户端的 Fonts 目录下面,但是我又想在程序中使用它. 这段代码放在哪里? 字体文件需要放到要安装的机器上吗?并不需要 System.Drawing.Text.PrivateFontCo ...

  7. 好代码是管出来的——使用Git来管理源代码

    软件开发过程中一个重要的产出就是代码,软件的编码过程一般是由一个团队共同完成,它是一个并行活动,为了保证代码在多人开发中能够顺利完成,我们需要使用代码版本控制工具来对代码进行统一存储,并追踪每一份代码 ...

  8. Get,Post请求方式经典详解

    本文转自:http://blog.csdn.net/findsafety/article/details/47129021 前几天工作中,所有表单我都采用post方法,头儿说那样不好,大型网站上一般都 ...

  9. Java 读书笔记 (十一) Number & Math 类

    所有的包装类(Integer.Long.Byte.Double.Float.Short)都是抽象类Number的子类. 这种由编译器特别支持的包装称为装箱,所以当内置数据类型被当作对象使用的时候,编译 ...

  10. 树莓派.Raspberry Pi 3碰到"Unable to determine hardware version. I see: Hardware : BCM2835"错误的解决过程

    按pi4jp官方的安装指导(http://pi4j.com/install.html)进行安装 curl -s get.pi4j.com | sudo bash 安装完成后执行JAVA程序, 发现如下 ...