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. Spark的Streaming + Flume进行数据采集(flume主动推送或者Spark Stream主动拉取)

    1.针对国外的开源技术,还是学会看国外的英文说明来的直接,迅速,这里简单贴一下如何看: 2.进入到flume的conf目录,创建一个flume-spark-push.sh的文件: [hadoop@sl ...

  2. centos 6.9安装python 3.6

    .下载源码包在官网按照需要下载到本地 wget https://www.python.org/ftp/python/3.6.1/Python-3.6.1.tgz .解压源码包 tar -xvf Pyt ...

  3. jQuery和Zepto冲突问题【解决】

    特殊操作下,项目中同时引入这两个文件时,往往会有些冲突,应该加一句代码避免冲突 <script src="~/js/jquery-2.1.4.js"></scri ...

  4. 一起学Hive——总结各种Join连接的用法

    Hive支持常用的SQL join语句,例如内连接.左外连接.右外连接以及HiVe独有的map端连接.其中map端连接是用于优化Hive连接查询的一个重要技巧. 在介绍各种连接之前,先准备好表和数据. ...

  5. python全栈开发day85-查:数据表 数据头 增加列 展示多对多字段 反向解析编辑和删除按钮的url

    直接上代码: # spark/service/sites.py from django.conf.urls import url from django.shortcuts import HttpRe ...

  6. Python_面向对象_类2

    类的几个装饰器方法: @classmethod (类方法):使之无法访问实例变量 class Animal(object): def __init__(self, name): self.name = ...

  7. Mybatis关联一对多映射不能查询出所有的数据的问题

    在使用Mybatis进行一对多查询时,如果返回的是一个对象的话,可以发现将一对多的数据全都取出来了,但是这样的缺点是有很多值为null,我们更喜欢将返回值设为Map的形式,这样可以去除那些多余null ...

  8. Python argparse 模块

    Python argparse 模块 test.py: import argparse argparser = argparse.ArgumentParser(add_help=False) argp ...

  9. so插件化

    --摘自<android插件化开发指南> 1.local.properties添加配置 ndk.dir=/Users/jianqiang/Library/Android/sdk/ndk-b ...

  10. HDU-2177 取(2堆)石子游戏 (威佐夫博奕)

    Problem Description 有两堆石子,数量任意,可以不同.游戏开始由两个人轮流取石子.游戏规定,每次有两种不同的取法,一是可以在任意的一堆中取走任意多的石子:二是可以在两堆中同时取走相同 ...