运行时数据区

  1. 程序计数器(Program Counter)

      每个线程独占自己的程序计数器。如果当前执行的方式不是native的,那程序计数器保存JVM正在执行的字节码指令的地址,如果是native的,那程序计数器的值是undefined。

      此内存区域是唯一一个在Java虚拟机规范中没有规定任何OutOfMemoryError情况的区域。

  2. Java虚拟机栈

      每个线程独占自己的Java虚拟机栈,这个栈与线程同时创建,用于存储栈帧

      Java虚拟机栈所使用的内存不需要保证连续的。
  • StackOverflowError:线程请求分配的栈容量超过Java虚拟机栈允许的最大容量。
  • OutOfMemoryError:如果虚拟机栈可以动态扩展,在尝试扩展的时候无法申请到足够的内存,或者在创建新的线程时没有足够的内存去创建对应的虚拟机栈。
  1. Java堆

      Java堆可供各个线程共享,是给对象分配内存的区域,也是需要自动回收垃圾的区域。

      堆的容量可以是固定的,也可以随着程序执行的需求动态扩展,并在不需要时自动收缩。Java堆所使用的内存不需要保证是连续的。
  • OutOfMemoryError:实际所需的堆超过了自动内存管理系统能提供的最大容量。
  1. 方法区

      方法区可供各个线程共享。它存储每一个类的结构信息,例如:运行时常量池、字段和方法数据、构造函数和不同方法的字节码内容,还包括一些在类、实例、接口初始化时用到的特殊方法。

      方法区是Java堆的逻辑组成部分,虚拟机可以在这个区域不实现垃圾收集与压缩。JVM规范也不限定实现方法区的内存位置和编译代码的管理策略。

      方法区容量可以是固定的,也可以随着程序执行的需求动态扩展,并在不需要时自动收缩。方法区所使用的内存不需要保证是连续的。
  • OutOfMemoryError:方法区的内存空间不能满足内存分配请求。

  关于永久代和元空间

  JDK 8引入了元空间的概念,它和JDK 8之前的永久代都是方法区的实现,区别是,永久代使用Java虚拟机内存,而元空间使用本地内存,将类的元数据移至元空间,而字符串和类静态变量移至Java堆。

  引入元空间的主要原因有两个

  • 永久代内存容易发生内存泄露,即java.lang.OutOfMemoryError: PermGen
  • 移除永久代可以促进HotSpot JVM与 JRockit VM的融合,因为JRockit没有永久代。
  1. 运行时常量池

      运行时常量池是class文件中每一个类或接口的常量池表的运行时表示形式。

      运行时常量池在方法区中分配,在加载类和接口到虚拟机后,就创建对应的运行时常量池。
  • OutOfMemoryError:方法区的内存空间不能满足内存分配请求。
  1. 本地方法栈

      JVM用本地方法栈来支持native方法。如果需要支持native方法,这个栈与线程同时创建。
  • StackOverflowError:线程请求分配的栈容量超过本地方法栈允许的最大容量。
  • OutOfMemoryError:如果本地方法栈可以动态扩展,在尝试扩展的时候无法申请到足够的内存,或者在创建新的线程时没有足够的内存去创建对应的本地方法栈。
  1. 直接内存

      不是Java虚拟机规范定义的内存,不属于运行时数据区,JDK NIO中基于通道与缓冲的I/O方式,可以直接分配堆外内存。直接内存受本机总内存的限制。
  • OutOfMemoryError:动态扩展导致总内存超过物理内存时。

    分配内存的两种方式

  1. 指针碰撞:内存是绝对规整的,用过的内存和空闲的内存分别放在堆的两边,中间放着一个指针作为分界点的指示器,分配内存就是指针往空闲区域移动与对象大小相等的距离。
  2. 空闲列表:内存是不规整的,虚拟机维护一个列表,记录哪些内存是可以使用的,分配内存就是从列表中找到一块足够大的内存划分给对象实例。

选择哪种分配方式由Java堆内存是否规整来决定,而Java堆是否规整又由所用的垃圾收集器是否带有压缩整理功能决定。因此,Serial、ParNew等带压缩过程的收集器采用指针碰撞,而CMS这种基于Mark-Swap算法的收集器采用空闲列表。

如何保障分配内存时的线程安全性?

  1. 使用CAS技术保证操作的原子性。
  2. 每个线程在堆中预先分配一小块内存称本地线程分配缓冲(TLAB)。哪个线程要分配内存,就在哪个线程的TLAB上分配。当TLAB用完,分配新的TLAB时加锁。

对象的内存布局和访问

  Java虚拟机在堆中给对象分配内存,对象在内存中的布局分为三块

  1. 对象头:存储了Mark Word、类型指针,如果是数组对象,还记录了数据长度。
  2. 实例数据:对象的真实数据。
  3. 对齐填充:由于对象大小必须是8字节的整数倍,所以需要占位符来对其填充。

 主流的对象访问方式

  1. 使用句柄访问:Java堆中划分一块内存作为句柄池,引用类型指向对象的句柄地址,句柄中包含对象实例数据与类型数据的地址。
  2. 使用直接指针访问:引用类型指向对象地址,堆中存储访问类型数据的信息。

  Hotspot虚拟机使用直接指针的方式来访问对象。节省了一次指针定位的时间开销。

如下图,展示了对象在内存的布局和访问方式。

参考资料:《深入理解Java虚拟机(第二版)》《Java虚拟机规范(Java SE 8版)》

Java虚拟机知识点【内存】的更多相关文章

  1. java虚拟机的内存机制

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

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

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

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

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

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

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

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

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

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

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

  7. java虚拟机的内存模型

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

  8. Java虚拟机的内存管理

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

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

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

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

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

随机推荐

  1. 关于DDD领域驱动设计的理论知识收集汇总

    原文:关于DDD领域驱动设计的理论知识收集汇总 最近一直在学习领域驱动设计(DDD)的理论知识,从网上搜集了一些个人认为比较有价值的东西,贴出来和大家分享一下: 我一直觉得不要盲目相信权威,比如不能一 ...

  2. Android零基础入门第70节:ViewPager轻松完成TabHost效果

    上一期学习了ViewPager的简单使用,本期一起来学习ViewPager的更多用法. 相信很多同学都使用过今日头条APP吧,一打开主界面就可以看到顶部有很多Tab,然后通过左右滑动来切换,就可以通过 ...

  3. 企业级架构 MVVM 模式指南 (WPF 和 Silverlight 实现) 译(1)

    前言对于WPF和Silverlight来讲,MVVM是微软设计师和业内专家高度推荐的非常棒的一种设计模式.本书会探讨MVVM设计模式的一些自身缺陷以及为什么MVVM还不能成为行业内的标准设计模式.这会 ...

  4. 常用json解析库比较及选择 fastjson & gson

    一.常用json解析库比较及选择 1.简介 fastjson和gson是目前比较常用的json解析库,并且现在我们项目代码中,也在使用这两个解析库. fastjson 是由阿里开发的,号称是处理jso ...

  5. VS2013设置release版本可调试

    http://blog.csdn.net/caoshangpa/article/details/76575640

  6. Java面试通关宝典

    1.说说Java中异常的分类: 答:可分为Error和Exception. 从概念角度分析: Error:是程序无法处理的系统错误,编译器不做检查: Exception:是程序可以处理的异常,捕获后可 ...

  7. Centos7 fstab盘符挂载硬盘导致重启系统失败解决办法

    服务器拥有多个硬盘插槽,在进行维护或重启时,这些硬盘的相对位置可能发生变化.利用盘符(dev/vda)方式挂载磁盘,可能由于磁盘顺序变化导致重启时读取fstab文件发生错误,从而无法正常重启服务器. ...

  8. python trojan development 2nd —— use python to send mail and listen to the key board then combine them

    请勿用于非法用途!!!!!本人概不负责!!!原创作品,转载说明出处!!!!! from pynput.keyboard import Key,Listener import logging impor ...

  9. 数据库读写分离Master-Slave

    数据库读写分离Master-Slave 一个平台或系统随着时间的推移和用户量的增多,数据库操作往往会变慢,这时我们需要一些有效的优化手段来提高数据库的执行速度:如SQL优化.表结构优化.索引优化.引擎 ...

  10. 移动IM开发指南3:如何优化登录模块

    <移动IM开发指南>系列文章将会介绍一个IM APP的方方面面,包括技术选型.登陆优化等.此外,本文作者会结合他在网易云信多年iOS IM SDK开发的经验,深度分析实际开发中的各种常见问 ...