文档章节

Java内存区域的划分和异常

架构师springboot
 架构师springboot
发布于 10/19 19:13
字数 1636
阅读 6
收藏 0

行时数据区域

JVM在运行Java程序时候会将内存划分为若干个不同的数据区域。

Java内存区域的划分和异常

程序计数器

线程私有。可看作是当前线程所执行的字节码的行号指示器,字节码解释器的工作是通过改变这个计数值来读取下一条要执行的字节码指令。

多线程是通过线程轮流切换并分配处理器执行时间来实现的,任何一个时刻,一个内核只能执行一条线程中的指令。为了线程切换后能恢复到正确的执行位置,每条线程都需要一个独立的程序计数器。这就是一开始说的“线程私有”。如果线程正在执行的方法是Java方法,计数器记录的是虚拟机字节码的指令地址;如果是Native方法,计数器值为空。程序计数器是唯一一个在Java虚拟机规范中没有规定OOM(OutOfMemoryError)情况的区域

Java虚拟机栈

线程私有,生命周期和线程相同。Java虚拟机栈描述的是Java方法的内存模型:每个方法在执行时都会创建一个栈帧,存储局部变量表、操作数栈、动态链接、方法出口信息,每一个方法从调用到结束,就对应这一个栈帧在虚拟机栈中的进栈和出栈过程。局部变量表保存了各种基本数据类型(int、double、char、byte等

)、对象引用(不是对象本身)和returnAddress类型(指向了一条字节码地址)。

这部分区域可能发生两种异常:

  • 线程请求的栈深度大于虚拟机所允许的深度,抛出StackOverflowError;
  • 虚拟机栈扩展时无法申请到足够的内存,抛出OutOfMemoryError。

本地方法栈

上述虚拟机栈为JVM执行Java方法服务,本地方法则为执行Native服务。其他和虚拟机栈类似,也会抛出StackOverflowError、OutOfMemoryError。

Java堆

常说的“栈内存”、“堆内存”,其中前者指的是虚拟机栈,后者说的就是Java堆了。Java堆是被线程共享的。在虚拟机启动时被创建。

Java堆的作用是存放对象实例,Java堆可以处于物理上不连续的内存空间中,只要求逻辑上连续即可。

方法区

线程共享的区域。存储已被虚拟机加载的类信息、常量、静态变量、即使编译器编译后的代码等数据。方法区无法满足内存分配需求时,抛出OutOfMemoryError。

运行时常量池

运行时常量池是方法区的一部分。C用于存放编译期生成的各种字面常量和符号引用,将在类加载后进入方法区的运行时常量池中存放。Java语言不要求常量只能在编译期产生,换言之,在运行期间也能将新的常量放入

直接内存

直接内存不属于虚拟机运行时数据区的一部分,也不是内存区域。本机直接内存的分配不会受到Java堆的大小限制,但终究是内存,如果各个内存区域总和大于物理内存限制,还是会出现OutOfMemoryError。

对象的创建过程

虚拟机遇到一条"new"指令:

  1. 首先检查这个指令的参数是否能在常量池中定位到一个类的符号引用;
  2. 检查这个符号引用代表的类是否已被加载、解析、初始化;(如果没有,则必须先进行类的加载)
  3. 在Java堆中为新对象分配内存,所需大小在类加载后就确定了;
  4. 将分配到的内存空间都初始化为0(不包括对象头)
  5. 类的初始化,即init方法,吧对象按照程序员的意愿初始化为想要的值。

对象的内存布局

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

  • 对象头
  • 实例数据
  • 对齐补充

对象头:存储对象自身的运行时数据,比如哈希码、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID等。另外还有一部分是类型指针,即对象指向它的类元数据的指针,虚拟机通过该指针来确定这个对象属于哪个类的实例。

实例数据:对象真正有效的信息,在程序中定义的各种类型的字段内容;

对齐补充:非必须,占用符的作用。

对象的访问定位

Java程序通过栈上的引用来操作堆上的实例对象。比如

Person p = new Person();

这里p就是引用,new出来的Person对象是实例。

这个引用没有规定要如何定位、访问堆中的对象具体位置。主流的有两中访问方式:

  • 句柄。Java堆中会划分出一块内存作为句柄池,引用存储了对象的句柄地址,而句柄中包含了对象实例数据和类型数据。好处是,对象被移动时,只需改变句柄中的地址,引用本身无需修改。
  • 直接指针。引用中存储的直接就是对象地址。好处是速度更快,由于引用直接表示实例对象的地址,节省了一次指针定位操作。Sun HotSpot使用的正是这种方式。

欢迎工作一到五年的Java工程师朋友们加入Java架构开发:855801563

群内提供免费的Java架构学习资料(里面有高可用、高并发、高性能及分布式、Jvm性能调优、Spring源码,MyBatis,Netty,Redis,Kafka,Mysql,Zookeeper,Tomcat,Docker,Dubbo,Nginx等多个知识点的架构资料)合理利用自己每一分每一秒的时间来学习提升自己,不要再用"没有时间“来掩饰自己思想上的懒惰!趁年轻,使劲拼,给未来的自己一个交代

 

© 著作权归作者所有

共有 人打赏支持
架构师springboot
粉丝 11
博文 69
码字总数 125203
作品 0
东城
私信 提问
Java虚拟机内存管理(一)—内存划分

Java 与 C++ 之间有一堵由内存动态分配和垃圾收集技术所围成的 “高墙”,墙外面的人想进去,墙里面的人却想出来。——《深入理解Java虚拟机:JVM高级特性与最佳时实践(第二版)》周志明 Ja...

Wizey
08/30
0
0
深入理解 Java 虚拟机学习(一) -- java 内存区域与内存溢出异常

java 内存区域 要进行 java 虚拟机的深入学习,首先要了解的是 java 的内存划分。大部分程序员一开始接触 java ,对于内存的划分是印象是堆内存和栈内存,而这仅仅适合于入门的学习,实际上 ...

偷星辰夜
2017/09/28
0
0
Java虚拟机-第一篇-Java内存区域与内存溢出异常

运行时候数据区域 橙色代表java虚拟机运行时候的线程共享的数据区域,绿色代表了运行时候线程的数据隔离区域。 程序计数器 程序计数器占用一小块内存区域,可以看做是当前线程所执行的字节码...

简心
09/30
0
0
深入了解java运行时的内存区域

对于java程序员来说,并不必显示地对内存进行管理,一切都交给java虚拟机去做吧,而且,你也不一定做得比java虚拟机来得专业。好像所有内存管理都交给虚拟机去做就万事大吉了,但是,事实有时...

依然范特西
2012/09/26
0
0
虚拟机学习之一:java内存区域与内存溢出异常

1.运行时数据区域 java虚拟机在执行java程序的过程中会把它所管理的内存划分为若干个不同的数据区域。这些区域都有各自的用途和创建、销毁时间,有的区域伴随虚拟机进程的启动而存在,有些区...

贾峰uk
10/21
0
0

没有更多内容

加载失败,请刷新页面

加载更多

SpringBoot源码:启动过程分析(二)

接着上篇继续分析 SpringBoot 的启动过程。 SpringBoot的版本为:2.1.0 release,最新版本。 一.时序图 一样的,我们先把时序图贴上来,方便理解: 二.源码分析 回顾一下,前面我们分析到了下...

Jacktanger
昨天
0
0
Apache防盗链配置,Directory访问控制,FilesMatch进行访问控制

防盗链配置 通过限制referer来实现防盗链的功能 配置前,使用curl -e 指定referer [root@test-a test-webroot]# curl -e "http://www.test.com/1.html" -x127.0.0.1:80 "www.test.com/1.jpg......

野雪球
昨天
2
0
RxJava threading

因为Rx针对异步系统设计,并且Rx也自然支持多线程,所以新的Rx开发人员有时会假设Rx默认是多线程的。在其他任何事情之前,重要的是澄清Rx默认是单线程的。 除非另有说明,否则每次调用onNex...

woshixin
昨天
0
0
Python的安装及文件类型、变量

一、为什么学习python 服务于大数据、人工智能、自动化运维。 简单易学 代码简洁 薪资高 近几年越来越火 二、Python的安装 linux 系统默认安装, CentOS7 默认安装了python2.7 安装ipython y...

枫叶云
昨天
1
0
JeeSite 4.x 树形结构的表设计和用法

有些同仁对于 JeeSite 4 中的树表设计不太了解,本应简单的方法就可实现,却写了很多复杂的语句和代码,所以有了这篇文章。 在 JeeSite 4 中的树表设计我还是相对满意的,这种设计比较容易理...

ThinkGem
昨天
34
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部