Java 内存区域
时间:2019-02-19
本文章向大家介绍Java 内存区域,主要包括Java 内存区域使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
- 以下内容为阅读 深入理解Java虚拟机(第2版)后的笔记及对 JDK8 的实践补充。看完这本书后最大的感觉就是,,,再看一遍,很多原来理解不了的知识点就可以看懂了,因为很多内容是前后呼应的。有兴趣的可以去阅读这本书,强推。
运行时数据区域
程序计数器
- 线程私有
- CPU 一般是分片运行的,线程转换的时候需要记录当前指令的位置,以便下一次运行时从中断处继续,这个就是程序计数器的作用。每一个线程有一个独立的程序计数器。
- 对于 Java 方法,计数器记录的是当前指令的地址;对于本地方法,则为 null。所以程序计数器不会发生 OutOfMemoryError
Java 虚拟机栈
- 线程私有
- 虚拟机栈描述的是 Java 方法(不包括本地方法) 执行的内存模型
每个方法执行时都会产生一个栈帧,用于存储 局部变量表,操作数栈 等信息。方法的执行就是其相对应的栈帧在虚拟机栈中入栈和出栈的过程
本地方法栈
- 对应于 Java 虚拟机栈,用来执行本地方法
- 很多虚拟机实现将 Java 虚拟机栈和本地方法栈合并,如 HotSpot
Java 堆
- 线程共享,但可以在堆中分配线程私有的分配缓冲区 (Thread Local Allocation Buffer,TLAB)
- 存放 Java 对象的位置,同时也是垃圾收集的主要区域(收集器现采用分代收集算法,将 Java 堆分成新生代和老年代等)
- Java 堆是物理上不连续,但逻辑上连续的内存区域,类似磁盘
JVM options | 作用 |
---|---|
-Xms | 堆的起始内存 |
-Xmx | 堆的内存上限 |
-Xmn | 堆的新生代所占内存大小,通常为堆的 1/4 |
-XX:+/-UseTLAB | 分配缓冲区的开关,server 模式默认开启 |
方法区
- 线程共享
- 方法区和堆很像,堆存放的是普通实例对象,而方法区存放的是 Class 对象 (类的加载)。为了与堆区分开来,方法区也被称为 Non-Heap。
- 方法区也用来存储虚拟机加载的类信息,常量,静态变量等数据。
- 运行时常量池 是方法区中一个很重要的区域,用来存储常量 (常量可以是编译 Class 文件时产生的,也可以是运行时产生的,所以成为运行时常量池)
早期 HotSpot 使用 永久代 来实现方法区,但很容易遇到内存溢出的错误,因为永久代是固定的,可以通过 -XX:MaxPermSize 来设置上限,但不方便。如今多采用 Native Memory 来实现方法区,上限为本地内存的容量(如 32 位系统的容量为 4G),Java8 已经废弃了 永久代,改而使用 元空间 来实现方法区。
直接内存
- 直接内存很特殊,它不算运行时数据区,但是很重要
Java 中的 nio 执行时使用的是本地内存,然后在虚拟机中通过对象来直接操作这部分内存,可理解为代理模式。这样可以避免数据在本地内存与堆内存的来回复制。这部分内存就被称为 直接内存 。
HotSpot 中的对象
ps:HotSpot 是 JDK 自带的虚拟机
对象创建
- 类加载检查
虚拟机遇到一个 new 指令时,先去常量池中检查是否含有这个类的符号引用,并且检查这个类是否已经被加载,解析与初始化过。(如果没有则先进行这些步骤)
- 为创建的对象分配内存
- 对象所需要的内存大小在类加载的时候就能够确定。
- 内存分配方式跟具体的虚拟机堆是否规范有关(如果堆内存把已用的放一边,空闲的放另一边,则堆是规整的;如果堆内存已用的和空闲的交错分布,则为不规整的。堆是否规整与收集器是否支持压缩整理功能有关,再深一点地讲,是否规整与收集器使用什么算法有关,使用复制算法和标记-整理算法为规整的,使用标记-清除算法为不规整的)。如果堆是规范的可直接将指针移动相应的大小(指针碰撞);如果堆是不规范的可在堆中维护一个空闲列表,记录堆中所有空闲的内存区域。
- 对象在虚拟机中创建是一种非常频繁的行为,即使只是最简单的修改指针的值,在多并发情况下还是很容易出错。常见的解决方法有:
* 通过 CAS(比较与交换)和错误重启的方式来保证更新操作的原子性;
* 通过 TLAB(本地线程分配缓冲区)来分配内存
- 初始化对象中内部对象的零值,如 int 变量为 0,Object 变量为 null 等
- 初始化对象头(Object Header)
- 最后执行 <init> 方法,初始化对象结束。
对象结构
- 对齐补充,起占位符的作用,因为 HotSpot 自动内存管理要求对象的大小是 8 个字节的整数倍。
- 对象头
- Mark Word,用来记录对象自身的运行时数据,包括哈希码,GC 分代年龄,锁状态标志等信息。
- 类型指针,用来指向方法区中与对象相对应的 Class 对象。(在 使用句柄来表示引用 的虚拟机中可以不要这部分数据,而 HotSpot 使用的是直接指针,所以需要类型指针。)
ps(句柄与直接指针):- 句柄中保存着 实例对象的引用 和 类型对象的引用。
- 垃圾回收之后经常会移动对象,如果使用句柄来表示引用的话,这个时候只需要改变句柄中指向实例对象的引用。但同时因为是间接的访问引用,所以不如直接指针快。
- 两种方式各有优缺,HotSpot 使用直接指针,也有大多数虚拟机使用句柄。
- 实例数据
- java教程
- Java快速入门
- Java 开发环境配置
- Java基本语法
- Java 对象和类
- Java 基本数据类型
- Java 变量类型
- Java 修饰符
- Java 运算符
- Java 循环结构
- Java 分支结构
- Java Number类
- Java Character类
- Java String类
- Java StringBuffer和StringBuilder类
- Java 数组
- Java 日期时间
- Java 正则表达式
- Java 方法
- Java 流(Stream)、文件(File)和IO
- Java 异常处理
- Java 继承
- Java 重写(Override)与重载(Overload)
- Java 多态
- Java 抽象类
- Java 封装
- Java 接口
- Java 包(package)
- Java 数据结构
- Java 集合框架
- Java 泛型
- Java 序列化
- Java 网络编程
- Java 发送邮件
- Java 多线程编程
- Java Applet基础
- Java 文档注释
- PHP中引用类型和值类型功能与用法示例
- PHP文件上传小程序 适合初学者学习!
- php的扩展写法总结
- 实例介绍PHP删除数组中的重复元素
- Python迭代器协议及for循环工作机制详解
- PHP CURL中传递cookie的方法步骤
- PHP 结合 Boostrap 结合 js 实现学生列表删除编辑及搜索功能
- Yii2处理密码加密及验证的方法
- PHP实现获取ip地址的5种方法,以及插入用户登录日志操作示例
- python如何输出反斜杠
- 在Laravel5中正确设置文件权限的方法
- asp函数split()对应php函数explode()
- php获取目录下所有文件及目录(多种方法)(推荐)
- Python基于Twilio及腾讯云实现国际国内短信接口
- PHP __call()方法实现委托示例