JDK1.8之前,java内存分为 线程共享区:堆、方法区、直接内存(非运行时数据区的一部分)。线程私有区:程序计数器、虚拟机栈、本地方法栈。

JDK1.8开始,虚拟机取消了方法区,改为元空间。

程序计数器:

程序计数器是一块小的内存空间,存放线程执行的信息,如字节码的行号指示器还有分支、循环、跳转、异常处理等都需要依赖计数器来完成。就是记录程序运行到哪个位置了,这样方便线程切换后能恢复到正确的执行位置,每个线程都需要有一个独立的程序计数器,所以它是线程私有的。它的生命周期随着线程的创建而创建,随着线程的结束而死亡。并且是唯一一个不会出现OutOfMemoryError的内存区域。

Java虚拟机栈:

它的生命周期也和线程相同,是线程私有的,描述的是java方法执行的内存模型,每次方法调用的数据都是通过栈传递的。Java虚拟机栈是由一个个栈帧组成,每个栈帧中都拥有:局部变量表、操作数栈、动态链接、方法出口信息。

局部变量表主要存放了编译器可知的各种数据类型(八大基本数据类型)和对象引用。

它会出现两种异常:StackOverFlowError和OutOfMemoryError。

StackOverFlowError:虚拟机栈的内存不允许动态扩展,当线程请求栈的深度超出当前栈深度,就会抛出该异常。

OutOfMemoryError:虚拟机栈的内存大小允许动态扩展,且当线程请求时内存用完了,无法再动态扩展了就会抛出该异常。

每一次函数调用都会有一个对应的栈帧被压入栈,调用结束后,栈帧就会被弹出。无论是return还是抛出异常都会导致栈帧弹出。

本地方法栈:

听名字就知道,这是一个执行本地方法(Native方法)时候使用的栈。虚拟机栈是执行java方法的时候使用的栈。其它工作原理跟java虚拟机栈一样,只是服务的对象不一样而已,这里就不做介绍了。

堆(Heap):

作为虚拟机内存中最大的一块区域,这是一块共享的内存区域,在虚拟机启动的时候创建。这个区域存放对象的实例,几乎所有的对象实例以及数组都在这里分配内存。这一块也是垃圾收集器主要管理的区域,现在收集器基本都采用分代收集算法,内存区域也可以大致划分为新生代和老年代。对象从新生代到老年代的年龄阈值可以通过参数设置。

 

方法区:

与堆一样也是线程共享的内存区域,它用于存储已经被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。这个区域常被称作“永久代”,但实际上,垃圾收集行为在这个区域只是比较少出现,但并非数据进入方法去后就永久存在了。

运行时常量池:

它是方法区的一部分,(用于存放编译期生成的各种字面量和符号引用)

JDK1.7之后的版本的JVM已经将运行时常量池从方法区中移了出来,在java堆中开辟了一块内存区域用来存放运行时常量池。

直接内存:

直接内存并不是虚拟机运行时数据区的一部分,也不是虚拟机规范中定义的内存区域,但是这部分内存也被频繁地使用。而且也可能导致OutOfMemoryError异常的出现。

对象的创建过程:

第一步:类加载检查

虚拟机遇到一条new指令时,首先将去检查这个指令的参数是否能在常量池中定位到这个类的符号引用,并且检查这个符号引用代表的类是否已被加载过、解析和初始化过。如果没有,那必须先执行相应的类加载过程。

第二步:分配内存

在类加载检查通过后,接下来虚拟机将为新生对象分配内存。对象所需的内存大小在类加载检查完成后便可确定,为对象分配空间的任务等同于把一块确定大小的内存从java堆中划分出来。分配方式有指针碰撞空闲列表两种方式,指针碰撞需要内存规整,即没有内存碎片的时候使用该方法;空闲列表则是在有内存碎片的情况下使用。

第三步:初始化零值

内存分配完成后,虚拟机需要将分配到的内存空间都初始化为零值(不包括对象头),这一不操作保证了对象的实例字段在java代码中可以不赋初值就直接使用,程序能访问到这些字段的数据类型所对应的零值。

第四步:设置对象头

初始化零值完成之后,虚拟机要对对象头进行必要的设置,例如这个对象是哪个类的实例、如何才能找到类的元数据信息、对象的哈希码、对象的GC分代年龄等信息。这些信息存放在对象头中。

第五步:执行init方法

在上面工作都完成之后,从虚拟机的视角来看,一个新的对象已经产生了,但从java程序员的视角来说,对象创建才刚刚开始,init方法还没有执行,所有的字段都是为零。所以一般来说,执行new指令之后会接着执行init方法,把对象按照程序员的意愿进行初始化,这样一个真正的可用的对象才算完全生产出来。

对象的访问定位:

句柄:使用句柄的方式的话,java堆中会划分一块内存来作为句柄池,reference中存储的就是对象的句柄地址,而句柄中包含了对象实例数据与类型数据各自的具体地址信息。访问对象时需要两次定位操作,先定位到句柄,再通过句柄的地址信息定位到对象。但是当对象被移动时只会改变句柄中的实例数据指针,reference不需要修改。

直接指针:reference存放的直接就是对象的地址。只需要一次指针定位,速度快。

Java虚拟机的内存的更多相关文章

  1. 如何写出让java虚拟机发生内存溢出异常OutOfMemoryError的代码

    程序小白在写代码的过程中,经常会不经意间写出发生内存溢出异常的代码.很多时候这类异常如何产生的都傻傻弄不清楚,如果能故意写出让jvm发生内存溢出的代码,有时候看来也并非一件容易的事.最近通过学习< ...

  2. 深入理解java虚拟机【内存溢出实例】

    通过简单的小例子程序,演示java虚拟机各部分内存溢出情况: (1).java堆溢出: Java堆用于存储实例对象,只要不断创建对象,并且保证GC Roots到对象之间有引用的可达,避免垃圾收集器回收 ...

  3. 从Java虚拟机的内存区域、垃圾收集器及内存分配原则谈Java的内存回收机制

    一.引言: 在Java中我们只需要轻轻地new一下,就可以为实例化一个类,并分配对应的内存空间,而后似乎我们也可以不用去管它,Java自带垃圾回收器,到了对象死亡的时候垃圾回收器就会将死亡对象的内存回 ...

  4. Java虚拟机:内存模型详解

    版权声明:本文为博主原创文章,转载请注明出处,欢迎交流学习! 我们都知道,当虚拟机执行Java代码的时候,首先要把字节码文件加载到内存,那么这些类的信息都存放在内存中的哪个区域呢?当我们创建一个对象实 ...

  5. 初识:java虚拟机的内存划分

    什么是内存? 内存是计算机中的重要原件,临时存储区域,作用是运行程序.我们编写的程序是存放在硬盘中的,在硬盘中的程序是不会运行的,必须放进内存中才能运行,运行完毕后会清空内存.Java虚拟机要运行程序 ...

  6. java虚拟机的内存模型

    一.为什么要了解java虚拟机的内存模型 java虚拟机作为java代码运行的平台,是java技术的基石.了解java虚拟机的内存模型也就变得十分必要.它能帮助我们更好的了解java代码的运行机制,更 ...

  7. java虚拟机的内存机制

    我们都知道,java程序的跨平台性离不开java虚拟机,虚拟机隔绝了底层操作系统,使得java程序可以直接运行在虚拟机之上.所以,对java的学习,离不开对java虚拟机的学习与了解.下面简单整理下j ...

  8. Java虚拟机的内存管理

    众所周知,Java程序员写的代码是没有办法控制Java对象的内存释放的,完全有JVM暗箱操作. 虽然程序员把内存的释放的任务都交给了Java虚拟机,但是并不代表Java程序就不存在内存泄漏. 反而,某 ...

  9. 1 - JVM随笔分类(java虚拟机的内存区域分配(一个不断记录和推翻以及再记录的一个过程))

    java虚拟机的内存区域分配   在JVM运行时,类加载器ClassLoader在加载到类的字节码后,交由jvm的执行引擎处理, 执行过程中需要空间来存储数据(类似于Cpu及主存),此时的这段空间的分 ...

  10. JAVA虚拟机:内存各个区介绍

    概述:java应用程序由java虚拟机自动管理程序执行期间内存管理. 优势:1.不再需要程序员去为使用的内存在程序中手动编写释放内存代码. 2.由虚拟机管理内存不容易出现内存泄漏和内存溢出的问题. 缺 ...

随机推荐

  1. springboot学习(二十二)_ 使用@Constraint注解自定义验证注解

    最近项目在使用如@NotNull @Max 等配合@vaild 注解进行验证传过来的参数校验,然后通过统一异常处理,直接返回给前端,不用在业务代码中对这些参数进行校验.但是官方提供的并不能全部满足项目 ...

  2. office visio 2019 下载激活

    安装 下载 office ed2k://|file|cn_office_professional_plus_2019_x86_x64_dvd_5e5be643.iso|3775004672|1E4FF ...

  3. The usage of Markdown---目录

    更新时间:2019.09.14   当我们编辑的内容比较多时,通常要生成目录来进行页内跳转.除了之前提到过的页内跳转链接的方法,还有一种方法--目录树,能够自动生产目录,大大减少工作量. tip1: ...

  4. win8 批处理自动填写ip

    本文适用于,经常把电脑来回带而又每次都得改ip的人 有木有觉得,这很麻烦,而又必须得这样做? 人真是因为懒惰而变得聪明.如果你不想每次重复填写,有幸百度到了这篇文章,感谢你的阅读. 现在我把研究成果共 ...

  5. vue路由安装

    1.安装路由: vue ui cnpm install vue-router 2.使用,导入: 默认创建项目的时候就已经帮你写好了. import router from "vue-rout ...

  6. 2018.8.13 python中生成器和生成器表达式

    主要内容: 1.生成器和生成器函数 2.列表推导式 一.生成器 生成器是指就是迭代器,在python中有三种方式来获取生成器: 1.通过生成器函数 2.通过各种推导式来实现生成器 3.通过数据的转换也 ...

  7. 基本的sql 语句

    1,登陆数据库:mysql -u root -p2,退出数据库:exit quit ctr+d3,创建数据库:create database 数据库名 charset=utf84,使用数据库:use ...

  8. Java内存模型相关原则详解

    在<Java内存模型(JMM)详解>一文中我们已经讲到了Java内存模型的基本结构以及相关操作和规则.而Java内存模型又是围绕着在并发过程中如何处理原子性.可见性以及有序性这三个特征来构 ...

  9. 机器阅读理解(看各类QA模型与花式Attention)

    目录 简介 经典模型概述 Model 1: Attentive Reader and Impatient Reader Model 2: Attentive Sum Reader Model 3: S ...

  10. 从函数计算架构看 Serverless 的演进与思考

    作者 | 杨皓然  阿里巴巴高级技术专家 导读:云计算之所以能够成为 DT 时代颠覆性力量,是因为其本质是打破传统架构模式.降低成本并简化体系结构,用全新的思维更好的满足了用户需求.而无服务器计算(S ...