Skip to content

Instantly share code, notes, and snippets.

@xiuhy
Last active July 30, 2017 06:54
Show Gist options
  • Save xiuhy/8fc57f16eecd069205a591868bfcaedb to your computer and use it in GitHub Desktop.
Save xiuhy/8fc57f16eecd069205a591868bfcaedb to your computer and use it in GitHub Desktop.
深入理解java 虚拟机笔记

主要记录学习《深入理解java 虚拟机笔记》图书过程中个人比较关注内容

[toc]

java 内存区域与内存溢出异常

运行时数据区域(jvm 内存模型)

java虚拟机运行时数据区

程序计数器

是一块较小的内存空间,可以看作是当前线程所执行的字节码的行号指示器。每条线程都有一个独立程序计数器,相互独立存储! 如果执行java方法,则计数器指向执行的字节码地址;如果是native的方法,则为空。 该区域是java虚拟机规范中唯一一个没有规定任何OOM的区域

Java 虚拟机栈

  • java 方法执行的内存模型:每个方法执行的同时会创建一个栈帧(Stack Frame)用于存储局部变量表,操作数栈,动态链接,方法出口等信息。每个方法从调用到直至完成,对应这一个栈帧在虚拟机栈中的入栈到出栈过程。
  • 局部变量存放三种类型数据:
  1. 基本类型数据
  2. 对象引用
  3. returnAddress类型(指向一条字节码指令的地址,具体咱不明白)
  • 线程私有且生命周期和线程相同
  • java虚拟机规范规定该区域存在两种异常:  1. stackOverflowError  2. OOM

  • 存放对象实例。
  • 存在OOM方法异常
  • 线程共享

本地方法栈

  • 虚拟机调用Native方法一个过程,与虚拟机方栈比较相似

方法区

  • 主要用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码数据等
  • 线程共享

运行时常量池

  • 运行时常量池是方法区一部分,用于存储编译器生成的字面量和符号引用,这部分内容将在类加载后静茹方法区的运行时常量池中存放。 具有动态性,可以在运行时放入常量池常量
  • 存在OOM异常

直接内存

  • 直接内存(Direct Memory)并不是虚拟机运行时数据的一部分,也不是java虚拟机规范中定义的内存区域,但是使用频繁
  • NIO引入一种基于通道与缓冲区的I/O方式。可以直接Native函数调用堆外内存。通过存储在堆上DirectByteBuffer对象作为内存引用进行操作,避免java堆和native堆来回复制数据,提高性能

对象创建

一个java对象创建过程:

  1. new 指令触发时,首先检查参数是否在常量池中定位到类引用,并且检查该类是否被加载,解析,初始化过。
  2. 分配内存。
  3. 内存空间初始化为零
  4. 对对象进行必要设置(类的元数据信息,对象哈希码等存放对象头)
  5. 实现init方法初始化对象

对象内部布局

HotSpot虚拟机中,对象在内部存储布局为3区域:对象头(Header)实际数据对齐填充

  • **对象头(Mark word)**主要包括两个部分  1. 存储对象本身的运行数据  2. 类型指针,即对象指向它的类元数据,虚拟机通过这个指针来确定这个对象是哪个类实例
  • 实例数据  继承父类,子类中定义的全部存储。
  • 对齐填充  由于HotSpot vm 自动内存管理系统必须要求对象起始地址必须8字节的整倍数,所以起到对为满八位倍数的占位符作用  

对象访问定位

reference 类型只存储一个对象引用地址,对象访问定位就是具体获取对象具体位置方法。目前主流两种方法:句柄,直接指针

  • 句柄 优点:1.reference中存储是稳定的句柄地址,发生对象被移动(垃圾回收)只会改变句柄中地址,reference不需要发生改变  
  • 直接指针 有点:1. 访问速度快。  

java 内存模型与线程

线程安全与锁优化

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment