Java虚拟机的内存空间分为五个部分,分别是:

  1. 程序计数器;
  2. Java虚拟机栈
  3. 本地方法栈
  4. 方法区

接下来对这五部分分别进行详细的介绍

1、程序计数器:

  a)什么是程序计数器:程序计数器是内存中的一个很小的空间,可以看作是当前线程正在执行的字节码的行号指示器。也就是说,程序计数器里面记录的是当前线程正在执行的字节码指令的地址。需要注意的是:如果当前线程正在执行的是一个本地方法,那么此时程序计数器为空。

b)  程序计数器的作用:字节码解释器通过改变程序计数器依次读取指令,实现程序的流程控制;在多线程的情况下,程序计数器用来记录当前线程的执行位置,以便于当线程被切回来的时候能够记住该线程上次运行到那里了。

c) 程序计数器的特点:是一块较小的内存空间;线程私有,每一个线程都有一个程序计数器;是唯一一个不会出现OutOfMemoryError的区域;生命周期随着线程的创建而创建,线程的结束而死亡。

2、Java虚拟机栈

a) 什么是Java虚拟机栈:Java虚拟机栈是描述Java方法运行过程的内存模型。Java虚拟机会为每一个即将运行的java方法创建一个叫“栈帧”的区域,该区域用来存放Java方法运行过程中需要的一些信息,这些信息主要包括:局部变量表、操作数栈、动态链接、方法出口信息等。

注意:当方法在运行过程中需要创建局部变量的时,就会将变量的值存入局部变量表中。人们常说的Java内存空间分为“栈”和“堆”,栈中存放的是局部变量,堆中存放的是对象,这句话是不完全正确的,几乎所有的对象都是存放在堆中,但是Java虚拟机会为每一个Java方法创建一个“栈帧”,其中栈帧包括局部变量表,但还包括其他的如操作数栈、动态链接和方法出口信息等。

b)Java虚拟机栈的主要特点:

  1) 局部变量表的创建是在Java方法即将运行的时候随着栈帧的创建而创建,但是局部变量表的大小是在编译阶段就已经确定的,创建的时候只是按照实现分配好的大小进行创建,而且在Java方法运行的过程中局部变量表的大小不会改变。

  2)Java虚拟机栈是线程私有的,每个线程都有自己的Java虚拟机栈,并且随着线程的创建而创建,随着线程的结束而死亡。

  3) Java虚拟机栈一般会出现两种错误:StackOverFloeError和OutOfMemoryError。

若Java虚拟机栈的内存大小不允许动态扩展,那么当线程请求栈的深度超过当前Java虚拟机栈的最大深度的时候,就抛出StackOverFlowError异常。StackOverFlowError表示当前线程申请的栈超过了事先定好的栈的最大深度,但内存空间可能还有很多。

若Java虚拟机栈的内存大小允许动态扩展,且当线程请求栈时内存用完了,无法再动态扩展了,此时抛出OutOfMemoryError异常。而OutOfMemoryError是指当线程申请栈时发现栈已经满了,而且内存也全都用光了。

3、本地方法栈

  a)什么是本地方法栈:

    1) 本地方法栈和Java虚拟机栈实现的功能类似,只不过本地方法栈是描述本地方法运行过程的内存模型。

    2)本地方法栈也是在方法即将运行被执行的时候,本地方方法栈也会为本地方法创建一个栈帧,用于存放该本地方法在运行过程中需要用到的一些信息。包括:局部变量表、操作数栈、动态链接、方法出口信息等。

    3) 本地方法在执行完毕也会将相应 的栈帧出栈并释放内存空间。

    4) 本地方法栈也会抛出StackOverFlowError和OutOfMemoryError异常。

4、堆

a) 什么是堆

堆是用来存放对象的内存空间,几乎所有的对象都存储在堆中。

 b)堆的特点是什么

  1)线程共享:整个虚拟机只有一个堆,所有的线程都访问同一个堆。

  2)在虚拟机启动的时候创建堆,在虚拟机关闭的时候销毁堆

  3)堆是垃圾回收的主要场所

  4) 堆可以进一步分为新生代和老年代,其中新生代有可以进一步分为Eden、From Survior、To Survior.不同的区域存放不同声明周期的对象,这样可以根据不同的区域使用不同的垃圾收集算法,从而是对象回收而更具有针对性,也会变的更加高效。

  5)  堆的大小即可以固定也可以动态的扩展,但是主流的虚拟机堆的大小都是可以动态扩展的。

5、方法区

  a)什么是方法区

在Java虚拟机规范中定义方法区是堆的一个逻辑部分,方法区中存放已经被虚拟机加载的类信息、常量、静态常量、即时编译器编译后的代码等

  b) 方法区的特点

        1)  线程共享:方法区是堆的一个逻辑部分,因此和堆一样是线程共享的,整个虚拟机中只有一个堆区域。

    2)永久代:方法区中存放的都是需要永久保存的信息,而且它还是堆空间的一个逻辑部分,因此用堆的方法进行划分把方法区分为老年代。

    3) 内存回收效率低:方法区中的信息一般需要长期存在,内存回收一遍只有少量的信息是无效的,在方法区中垃圾回收的主要对象是对常量池的回收和对类型的卸载。

    4)Java虚拟机规范对方法区的要求比较宽松:和堆一样允许固定大小,也允许动态扩展,还允许不进行垃圾回收。

  c)  什么是运行时常量池

  一般在一个类中通过public static final来声明一个常量,这个类被编译之后会生成一个Class文件,这个类的全部信息都会包含在这个Class文件中,当这个类被虚拟机加载之后,Class文件中的常量就会被放在方法区的运行时常量池中。在程序运行期间,也可以向常量池中添加常量。如果运行时常量池中的常量长时间没有被对象引用,也没有被变量引用,那么就会被垃圾收集器进行回收。

6、直接内存

直接内存是除了Java虚拟机之外的内存,但也能被Java利用。在NIO中引入了一种基于通道和缓冲的IO方式,它可以通过调用本地方法直接分配Java虚拟机之外的内存,然后通过一个存储在Java堆中的DirectByteBuffer对象直接操作该内存,从而提升了数据操作的效率。

直接内存的大小不受Java虚拟机的控制,但既然是内存,当内存不足的时候也会出现抛出OOM异常。

综上所述:

a)Java虚拟机的内存模型中一共有两个“栈”,分别是:Java虚拟机栈和本地方法栈。两个“栈”的功能类似,都是方法运行过程的内存模型。并且两个“栈”内部构造相同,都是线程私有。只不过Java虚拟机栈描述的是Java方法运行过程的内存模型,而本地方法栈是描述Java本地方法运行过程的内存模型。

b)Java虚拟机的内存模型中一共有两个“堆”,一个是原本的堆,一个是方法区。方法区本质上是属于堆的一个逻辑部分。堆中存放对象,方法区中存放类信息、常量、静态变量、即时编译器编译的代码。

c)堆是Java虚拟机中最大的一块内存区域,也是垃圾收集器主要的工作区域。

d) 程序计数器、Java虚拟机栈、本地方法栈是线程私有的,即每个线程都拥有各自的程序计数器、Java虚拟机栈、本地方法区。并且他们的生命周期和所属的线程一样。

e)而堆、方法区是线程共享的,在Java虚拟机中只有一个堆、一个方法栈。并在JVM启动的时候就创建,JVM停止才销毁。

深入理解JVM(1)——JVM内存模型的更多相关文章

  1. (转载)JVM中的内存模型与垃圾回收

    转载自微信公众号:Java高级架构(Java-jiagou)-----看完这篇文章,我奶奶都知道JVM中的内存模型与垃圾回收了! 六.内存模型 6.1  内存模型与运行时数据区 Java虚拟机在执行J ...

  2. JVM学习笔记——内存模型篇

    JVM学习笔记--内存模型篇 在本系列内容中我们会对JVM做一个系统的学习,本片将会介绍JVM的内存模型部分 我们会分为以下几部分进行介绍: 内存模型 乐观锁与悲观锁 synchronized优化 内 ...

  3. 深入理解JVM(6)——Java内存模型和线程

    Java虚拟机规范中定义了Java内存模型(Java Memory Model,JMM)用来屏蔽掉各种硬件和操作系统的内存访问差异,以实现让Java程序在各种平台下都能达到一致的内存访问效果(“即Ja ...

  4. 深入理解JAVA虚拟机(内存模型+GC算法+JVM调优)

    目录 1.Java虚拟机内存模型 1.1 程序计数器 1.2 Java虚拟机栈 局部变量 1.3 本地方法栈 1.4 Java堆 1.5 方法区(永久区.元空间) 附图 2.JVM内存分配参数 2.1 ...

  5. 理解JVM之java内存模型

    java虚拟机规范中试图定义一种java内存模型(JMM)来屏蔽掉各种硬件和操作系统内存访问差异,以实现让java程序在各种平台都能打到一致的内存访问效果.所以java内存模型的主要目标是定义程序中各 ...

  6. 【JVM】JVM系列之内存模型(六)

    一.前言 经过前面的学习,我们终于进入了虚拟机最后一部分的学习,内存模型.理解内存模型对我们理解虚拟机.正确使用多线程编程提供很大帮助.下面开始正式学习. 二.Java并发基础 在并发编程中存在两个关 ...

  7. JVM学习--(二)内存模型、可见性、指令重排序

    我们将根据JVM的内存模型探索java当中变量的可见性以及不同的java指令在并发时可能发生的指令重排序的情况. 内存模型 首先我们思考一下一个java线程要向另外一个线程进行通信,应该怎么做,我们再 ...

  8. 【JVM】Java内存模型

    原文:多线程之Java内存模型(JMM)(一) 概述 多任务和高并发是衡量一台计算机处理器的能力重要指标之一.一般衡量一个服务器性能的高低好坏,使用每秒事务处理数(Transactions Per S ...

  9. jvm(12)-java内存模型与线程

    [0]README 0.1)本文部分文字描述转自“深入理解jvm”,旨在学习“java内存模型与线程” 的基础知识:   [1]概述 1)并发处理的广泛应用是使得 Amdahl 定律代替摩尔定律称为计 ...

  10. 看完这篇文章,我奶奶都知道什么是JVM中的内存模型与垃圾回收!

    扩展阅读:JVM从入门开始深入每一个底层细节 六.内存模型 6.1.内存模型与运行时数据区 Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干不同数据区域. Java内存模型的主要目 ...

随机推荐

  1. org.apache.zookeeper.KeeperException$ConnectionLossException: KeeperErrorCode = ConnectionLoss for /eclipse20171118

    1:如果有一天,你有幸看到了这个错误,也许你像我一样low,因为此时,你已经准备开发Zookeeper程序了,却还没有把Zookeeper的服务启动起来. org.apache.zookeeper.K ...

  2. 从oracle到mysql

    过去四年一直是使用oracle,现在要开始使用mysql了,对于使用中发现的不同之处,我在此记录 mysql在linux下表名区分大小写,windows下表名不区分大小写 mysql没有number类 ...

  3. 【总结】瞬时高并发(秒杀/活动)Redis方案(转)

    转载地址:http://bradyzhu.iteye.com/blog/2270698 1,Redis 丰富的数据结构(Data Structures) 字符串(String) Redis字符串能包含 ...

  4. bzoj 5099: [POI2018]Pionek

    题解: 还是比较简单的一道题 考虑现在有一个向量,当且仅当下一个向量与它夹角<90度这个向量的模长才会增加 接下来怎么做呢 如果我们去枚举初始向量,向量方向会随着新增向量而变化 随着不断顺时针的 ...

  5. DC3求后缀数组板子

    #include<bits/stdc++.h> #define LL long long #define fi first #define se second #define mk mak ...

  6. Python 经典类和新式类

    #!/usr/bin/env python# -*- coding:utf-8 -*-# 作者:Presley# 邮箱:1209989516@qq.com# 时间:2018-10-21# 新式类和经典 ...

  7. eclipse中设置自动生成的author,date等注释

    转自:http://blog.csdn.net/zhouhong1026/article/details/38396311 转自:http://hi.baidu.com/qianjian21/blog ...

  8. Tomcat启动分析(转自:http://docs.huihoo.com/apache/tomcat/heavyz/01-startup.html)

    Tomcat启动分析 1 - Tomcat Server的组成部分 1.1 - Server A Server element represents the entire Catalina servl ...

  9. MongDB-高级

    No1: 聚合 聚合(aggregate)主要用于计算数据,类似sql中的sum().avg() ---语法 db.集合名称.aggregate([{管道:{表达式}}]) No2: 管道 管道在Un ...

  10. Codeforces 853B Jury Meeting (差分+前缀和)

    <题目链接> 题目大意: 有$ n(n<=1e5)$个城市和一个首都(0号城市),现在每个城市有一个人,总共有$ m (m<=1e5)$次航班,每个航班要么从首都起飞,要么飞到 ...