一、Java内存区域及内存溢出异常

1、运行时数据区域

  

 

  1、程序计数器:当前线程所执行的字节码的行号指示器。

    场景理解:并发中,CPU在不同线程间切换,为了线程切换后能恢复到正确的执行位置,每个线程都有程序计数器来记录执行位置。

  2、虚拟机栈:生命周期与线程相同。

    虚拟机栈描述的是Java方法执行的内存模型,每个方法在执行的同时会创建一个栈帧用于保存局部变量表,操作数栈,动态链接方法出口等信息。

    如果线程请求的栈大小无法申请到足够的内存,会抛出OutOfMemoryError。

  3、本地方法栈:

    虚拟机栈为Java方法(字节码,class文件)服务;

    本地方法栈为Native(本地)方法服务。

  4、堆:存放对象实例

    堆是GC管理的主要区域。

  5、方法区:存储已被加载的类信息,常量,静态变量等

    运行时常量池在方法区中。

二、对象

1、创建对象线程安全问题

  创建对象在堆上划分空间时,通过修改指针指向位置实现。在并发下,会出现线程安全问题。存在两种解决方案:

  1、采用CAS机制保证操作原子性

  2、采用TLAB(Thread Local Allocation Buffer,本地线程分配缓冲)即每个线程在Java堆中预先分配一块内存,每个线程单独分配内存。

2、对象的内存布局

  对象在内存中存储的布局可以分为3块区域:

  1、对象头(Header)

    分为两部分:第一部分用于存储对象自身的运行时数据,如哈希码,GC分代年龄,锁状态标识,线程持有的锁等,官方称其为“Mark Word”

               第二部分是类型指针,指向它的类元数据,虚拟机可以用此来确定对象是哪个类的实例。

    如果对象是一个数组,则对象头中还有记录数组长度的数据。

  2、实例数据(Instance Data)

    在代码中定义的各种类型的字段内容。

  3、对齐填充(Padding)

    不是必然存在的,对象大小必须是8的倍数,不足8时,通过填充补齐。

3、访问对象

  1、句柄访问:java对中会分配一块内存作为句柄池,句柄中包含了对象实例数据与类型数据具体的地址信息。

  2、直接指针:栈中存放的直接就是对象地址(HotSpot采用方式)

 

 

    

    

 

 

  

 

posted on 2019-09-29 20:24  dysdhd  阅读(102)  评论(0)    收藏  举报