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. Vulnhub靶场渗透练习(三) bulldog

    拿到靶场后先对ip进行扫描 获取ip  和端口 针对项目路径爆破 获取两个有用文件 http://192.168.18.144/dev/ dev,admin 更具dev 发现他们用到框架和语言 找到一 ...

  2. C#初始类和命名空间

    本节内容: 1.剖析Hello,World程序 1.1初始类(class)与名称空间(namespace) 2.类库的引用 2.1DLL的引用(黑盒引用) 2.2项目引用(白盒引用) 2.3建立自己的 ...

  3. Could not initialize class com.fasterxml.jackson.databind.SerializationConfig

    问题 Spring web 与 Spring eureka集成后出现错误: Caused by: java.lang.NoClassDefFoundError: Could not initializ ...

  4. 我遇到的一些Git问题汇编

    问题一: failed to push some refs to git hint: Updates were rejected because the remote contains work th ...

  5. Android开发高手课NOTE

    最近学习了极客时间的<Android开发高手课>很有收获,记录总结一下. 欢迎学习老师的专栏:Android开发高手课 内存优化 卡顿的原因 频繁 GC 造成卡顿.物理内存不足时系统会触发 ...

  6. Vuforia添加虚拟按键

    AR虚拟按键为真实识别图上的按键,通过按键可以实现真实与虚拟之间的按键交流 (一)添加按键 点击target,打开advance,添加虚拟按键,即可在此target下添加虚拟按键 注:虚拟按键无法旋转 ...

  7. git的使用和常用命令

    git介绍 git 是一个免费开源的分布式版本控制系统 git可以实现各个版本之间的来回穿梭 git可以远程托管代码 git可以完成团队合作 workspace --add--> index - ...

  8. 关于kaggle注册无法显示人机验证码问题

    最近准备做项目,需要在kaggle上下载数据集,但注册时遇到了无法显示验证图片信息的问题,我也是通过百度最终找到解决方法,所以就准备记录下来啦:下面是解决步骤: step1:下载Google访问助手 ...

  9. float使用0xFF

    1. float f = 0xFFFFFFFF; 这一句完全是错误的用法,它不会使f变量内存变为4个0xFF,因为0xFFFFFFFF根本就不是有效的float数值,编译器无从处理,如果用printf ...

  10. Spring Boot2 系列教程(二十)Spring Boot 整合JdbcTemplate 多数据源

    多数据源配置也算是一个常见的开发需求,Spring 和 SpringBoot 中,对此都有相应的解决方案,不过一般来说,如果有多数据源的需求,我还是建议首选分布式数据库中间件 MyCat 去解决相关问 ...