本文内容来自《深刻理解Java虚拟机》,主要是自身学习,用于记录重点,方便回忆,复习。对应《深刻理解Java虚拟机》第二章。并发
程序计数器(线程私有):可认为是线程执行字节码的行号指示器,经过该计数器的值,可知道线程下一条须要执行的字节码。循环、异常处理、线程恢复都须要依赖该计数器来完成。没个线程都一个独立程序计数器,各线程计数器互不影响独立存储,为“线程私有”。app
Java虚拟机栈(线程私有):通程序计数器,为“线程私有”,生命周期与线程相同。每一个方法执行都会建立栈帧,用于存储局部变量表、操做数栈等信息。局部变量表存放编译期可知的基本数据类型,对象引用。可能会出现两种异常:StackOverflowError:线程请求的栈深度大于虚拟机所容许的深度(如递归深度过深),OutOfMemoryError(扩展时没法申请到足够内存)。函数
本地方法栈(线程私有):与虚拟机栈做用相似,区别在于该区域是用于native本地方法。布局
Java堆(线程共享):虚拟机启动时建立,用于存放对象实例,垃圾收集器管理的主要区域,也称为“GC堆”,可处于物理上不连续的内存空间中,逻辑上是连续的便可。没法扩展内存时,会抛出OutOfMemoryError。学习
方法区(线程共享):用于存储被虚拟机加载的类信息,常量、静态变量。可能抛出OutOfMemoryError。ui
常量池:方法区的一部分,用于存放编译时生成的字面量、符号引用。可能会抛出OutOfMemoryError。编码
直接内存:NIO中引入,经过native函数库分配堆外内存,经过存储在堆中的DirectByteBuffer对象对这块内存进行操做。不受Java堆大小限制,编码Java堆与Native中来回复制数据。spa
一、假设Java堆中内存是绝对规整,用过的内存放一边,空闲的内存放另外一边,中间放一个指针做为分界线的指示器,为对象分配内存就仅仅是把指针向空闲空间那边挪动一段与内存大小相等的距离,这种分配方法称为“指针碰撞”。线程
二、若是内存不规整,虚拟机即需维护一个列表,记录哪块内存可用,分配时从列表中找出一块足够大内存划分给对象,并更新列表,称为“空闲列表”。指针
A线程读取指针分配内存还未结束,B线程读取旧指针分配内存,即会出现问题。
一、对内存空间分配动做进行同步处理,虚拟机上采用CAS,失败重试保证更新原子性。
二、把内存分配的动做按照线程划分在不一样的空间进行。即每一个线程在Java堆中预先分配一小块内存,称为本地线程分配缓冲。使用该方式,可经过-XX:+/-UseTLAB设定。
分为3块区域:对象头+实例数据+对齐填充
对象头分类两部分:一、对象运行时数据:哈希码、GC分代年龄、锁状态标志等。32位虚拟机下为32bit,64位虚拟机下为64bit。二、类型指针,指向它的类元数据的指针,经过该指针肯定对象是哪一个类的实例。
实例数据:从父类中继承的字段、类中定义的字段
对齐填充:对象其实地址必须是8字节的整数倍,若是对象头是8字节的1或2倍数,若是实例数据不是8字节的整数倍,继续填充。
访问对象:
一、经过引用访问对象 A a = new A(); a.getB():变量 --->引用池(句柄池,Java堆中)---> 对象
二、直接指针 new A().getB(): -----> 对象
参数:
-Xms20m 设置堆初始化内存20m。
-Xmx20m 设置堆最大内存20m。
-Xss 设置栈的大小。
-XX:MaxDireMemorySize 指定最大直接内存。
-XX:+HeapDumpOnOutMemoryError 让虚拟机出现内存益处时Dump出当前内存堆转存快照,便于过后分析。