您的位置:首页 > 编程语言 > Java开发

第二章、Java内存区域与内存溢出异常

2019-07-12 11:51 155 查看
版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。 本文链接:https://blog.csdn.net/u011780616/article/details/95603085

Java与C++的区别?

Java有自动内存管理,C++没有。

运行时数据区

  1. 程序计数器
    作用:执行Java方法,存放正在执行的字节码指令地址;执行本地方法,则为Undefined。
    大小:很小,存放正在执行的字节码指令地址。
    异常:存储内容固定,没有任何异常。
    线程私有:是线程私有的。
注意:
程序计数器与线程的上下文切换有关,进行上下文切换时,工作内容保存在程序计数器中。所以程序计数器必须是线程私有的。
  1. Java虚拟机栈
    作用:代表Java方法执行的内存模型,方法执行入栈,方法结束出栈,代表一个线程执行的所有方法过程。
    大小:动态可扩展
    异常:StackOverflowError和OutOfMemoryError
    线程私有:是线程私有的
注意:
栈帧
作用:一个栈帧代表一个方法的执行,存放局部变量表,操作数栈和动态链接等。
大小:编译期确定。
异常:无。
线程私有:是线程私有的。
局部变量表存放各种局部变量,64位变量占用两个slot,其它一个;使用下标代表局部变量在代码中的位置,从0开始,一般0代表this。
操作数栈:存放各种操作数以及中间结果。
  1. Java堆
    作用:存放对象实例。
    大小: 动态扩展
    异常: OutOfMemoryError
    线程私有: 不是线程私有,是线程共享的
注意:
Java堆是垃圾回收的主要区域,因为存放各实例对象,回收价值大。
Java堆可以划分为新生代和老年代,新生代可以划分为Eden区和From Survivor和To Survivor。
控制参数: -Xmx 最大值;-Xms 最小值。
  1. 方法区
    作用:存放常量,静态变量,类信息以及即时编译后的代码,是堆的逻辑区域。
    大小:可扩展。
    异常:OutOfMemoryError
    线程私有:不是线程私有,是线程共享的。
注意:
字符串常量池已经从方法区中移出。
JDK1.8以前使用永久代来进行垃圾回收,1.8之后使用元方法区替代。
  1. 运行时常量池
    作用:存放各种字面量和符号引用。
    大小:动态扩展
    异常:OutOfMemoryError
    线程私有:不是线程私有,是线程共享的。

Java对象的创建

  1. 首先在常量池中,能否定位到符号引用,并检查是否加载解析初始化过,不通过则执行加载解析初始化。
  2. 检查通过,为对象分配内存。
如果内存规整,使用指针碰撞,将指针移动对象所需空间大小即可。
内存不规整,使用空闲列表法,维护所有空闲的空间,从中查找符合大小的空间。
并发安全可以使用本地线程分配缓冲,为每个线程分配独立的空间,在自己的空间中创建对象。
也可以使用CAS保证线程安全。
  1. 分配完成,初始化零值。
  2. 设置对象头。
  3. 执行方法。
是否Start是否加载解析初始化分配内存加载解析初始化内存初始化零值设置对象头执行init方法End

对象内存布局

分为三部分,对象头,示例数据和对其填充。

对象头

对象头中第一部分存储自身运行时数据,称为Mark Word

状态 25bit hashCode 4bit 年龄分代 1bit 是否偏向锁 2bit 锁标记
无锁 hashCode age 0 01
状态 25bit hashCode 4bit 年龄分代 1bit 是否偏向锁 2bit 锁标记
GC 11
轻量级锁 指向栈中锁记录的指针 00
重量级锁 指向重量锁的指针 10
状态 23bit hashCode 2bit Espoh 4bit 年龄分代 1bit 是否偏向锁 2bit 锁标记
偏向锁 指向偏向的线程Id Espoh age 1 00

对象头第二部分存储类型指针,来确定是哪个类的实例。
如果是数组,还要有第三部分存放数组长度。

实例数据

存放各种类型的字段内容,父类的在前,子类在后,相同宽度的字段放在一起。

对象的访问定位

句柄池

优势是对象实例指针发生变化,栈中局部变量表到句柄池的引用不会变化,始终保持稳定。
缺点是需要两次指针定位。

直接指针

优势是只需要一次访问定位,速度快。

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: