对于Java程序员,在虚拟机自动内存管理机制的帮助下,不需要再为每一个操作写配对的释放资源操作,不容易出现内存泄露和内存溢出问题。加深对Java虚拟机的理解,有助于在发现问题时精准定位问题,排查错误因素,写出更健壮的代码。
一、虚拟机内存
Java虚拟机在执行Java程序时,会把它所管理的内存划分成若干个不同的数据区域。这些区域都有各自的用途,以及创建和销毁的时间。从粗略的角度来说,可以分为堆和栈。堆为线程公有,栈为线程私有。
1.1 程序计数器
程序计数器是一块较小的内存空间,它可以看做是当前线程所执行的字节码的行号指示器。字节码解释器工作时,就是通过改变这个计数器的值来选取下一条需要执行的字节码指令。
为了线程切换后能恢复到正确的执行位置,每个线程都需要有一个独立的程序计数器。各条线程之间的计数器互不影响、独立存储,称这类内存区域为“线程私有”的内存。
1.2 Java虚拟机栈、本地方法栈
Java虚拟机栈(Java Virtual Machine Stacks)也是线程私有的,它的生命周期与线程相同。虚拟机栈描述的是Java方法执行的内存模型:每个方法在执行的同时会创建一个栈帧(Stack Frame),用于存储局部变量表、操作数栈、动态链接、方法出口等信息,每一个方法从调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中入栈到出栈的过程。
1.3 堆、方法区
对于大多数应用来说,Java堆(Java Heap)是Java虚拟机所管理的内存中最大的一块。Java堆是被所有线程共享的一块内存区域,在虚拟机启动时创建。此内存区域的唯一目的就是存放对象实例,几乎所有的对象实例都在这里分配内存:所有的对象实例以及数组都要在堆上分配。
方法区(别名非堆:Non-Heap)是各个线程共享的内存区域,它用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。
1.4 运行时常量池
运行时常量池(Runtime Constant Pool)是方法区的一部分。——用于存放类加载后的编译信息
1.5 直接内存
2、对象
2.1 对象的创建
①运行时常量池-检查类是否已被加载
②为新生对象分配内存
指针碰撞 Bump the Pointer :假设Java堆中的内存是绝对规整的,内存区分为可用和已用两部分,中间用指针分隔,作为分界点的指示器。分配内存就是将指针向空闲区域移动与对象大小相等的距离。
空闲列表 Free List:Java堆中的内存并不规整,虚拟机维护一个列表,记录哪些内存块是可用的,在分配的时候从列表上找到一个足够大的空间划分给对象实例,并更新列表上的记录。
CAS/失败重试 Compare And Swap:保证分配内存的并发安全
TLAB:本地线程分配缓冲(Thread Local Allocation Buffer):每个线程在Java堆中预先分配一小块内存,哪个线程要分配内存,就先在TLAB上分配,只有当TLAB用完并分配新的TLAB时,才需要同步锁定
③对对象进行必要的设置
将对象信息存储在对象的对象头(Object Head)之中。
2.2 对象的内存布局
对象在内存中存储的布局可以分为3块区域:对象头(Header)、实例数据(Instance Data)、对齐填充(Padding)
①对象头:
Mark Word:存储对象自身的运行时数据,如哈希码(HashCode)、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID、偏向时间戳等。
类型指针:对象指向它的类元数据的指针,虚拟机通过这个指针来确定这个对象是哪个类的实例,若对象为一个Java数组,则对象头中还必须有一块用于记录数组长度的数据。
②实例数据
③补齐
虚拟机大小必须是8字节的整数倍,不规整的
3、运行测试
1、使用IDEA,设置虚拟机参数: -Xss参数,减小栈内存容量。
测试程序:
public class JavaVMStackSOF {
private int stackLength = 1;
private void stackLeak(){
stackLength ++;
stackLeak();
}
public static void main(String[] args) {
JavaVMStackSOF oom = new JavaVMStackSOF();
try{
oom.stackLeak();
}catch (Throwable e){
System.out.println("stack length:" + oom.stackLength);
throw e;
}
}
}
输出结果:
抛出StackOverflowError异常,异常时输出的堆栈深度相应缩小。
.png)
二、垃圾回收策略
1、引用
判断引用是否存在,用于判断对象是否存活。
在JDK1.2之后,Java对对象的引用概念进行扩充, 将引用分为强引用(Strong Reference)、软引用(Soft Reference)、弱引用(Weak Reference)、虚引用(Phantom
Reference)
强引用就是指在程序代码之中普遍存在的、类似于“Object obj = new Object()”这类的引用。只要强引用还存在,垃圾回收器就永远不会回收被引用的对象。
2、垃圾回收算法
①标记-清除算法
最基础的收集算法是“标记-清除”算法:分为“标记”和“清除”两个阶段:首先标记出所有需要回收的对象,在标记完成后统一回收所有被标记的对象。
主要不足:一是效率问题,标记和清除两个过程的效率都不高,二是空间问题,标记清除之后会产生大量不连续的内存碎片,空间碎片太多可能会导致在程序运行过程中,需要分配较大对象时,无法找到足够的连续内存而不得不提前触发另一次垃圾回收动作。
②复制算法
将可用内存划分为两部分,当一部分用完时,将这部分中所有还存活的对象复制到另一部分中,再将已使用过的内存空间一次清理掉。
③标记-整理算法
与标记-清除算法类似,但标记后的后续步骤不是直接对可回收对象进行清理,而是让所有存活的对象都向一端移动。
④分代收集算法
当前商业虚拟机的垃圾回收都采用“分代收集”算法。这种算法并没有什么新的思想,只是根据对象存活周期的不同,将内存划分为新生代、老年代。根据不同年代的特点,采用不同的回收算法。
3、垃圾回收器
①Serial收集器:
②G1收集器
对象优先在Eden分配:
大多数情况下,对象在新生代Eden区中分配,当Eden区没有足够空间进行分配时,虚拟机将发起一次Minor GC。
大对象直接进入老年代:所谓大对象是指需要大量连续内存空间的Java对象,最典型的的大对象就是很长的字符串以及数组。
- 《深入理解Java虚拟机》虚拟机性能监控与故障处理工具
上节学习回顾 从课本章节划分,<垃圾收集器>和<内存分配策略>这两篇随笔同属一章节,主要是从理论+实验的手段来讲解JVM的内存处理机制.好让我们对JVM运行机制有一个良好的概念 ...
- 《深入理解 java虚拟机》学习笔记
java内存区域详解 以下内容参考自<深入理解 java虚拟机 JVM高级特性与最佳实践>,其中图片大多取自网络与本书,以供学习和参考.
- (1) 深入理解Java虚拟机到底是什么?
好文转载:http://blog.csdn.net/zhangjg_blog/article/details/20380971 什么是Java虚拟机 作为一个Java程序员,我们每天都在写Java ...
- 深入理解java虚拟机(7)---线程安全 & 锁优化
关于线程安全的话题,足可以使用一本书来讲解这些东西.<Java Concurrency in Practice> 就是讲解这些的,在这里 主要还是分析JVM中关于线程安全这块的内容. 1. ...
- 深入理解java虚拟机(6)---内存模型与线程 & Volatile
其实关于线程的使用,之前已经写过博客讲解过这部分的内容: http://www.cnblogs.com/deman/category/621531.html JVM里面关于多线程的部分,主要是多线程是 ...
- 深入理解java虚拟机(5)---字节码执行引擎
字节码是什么东西? 以下是百度的解释: 字节码(Byte-code)是一种包含执行程序.由一序列 op 代码/数据对组成的二进制文件.字节码是一种中间码,它比机器码更抽象. 它经常被看作是包含一个执行 ...
- 深入理解java虚拟机(4)---类加载机制
类加载的过程包括: 加载class到内存,数据校验,转换和解析,初始化,使用using和卸载unloading过程. 除了解析阶段,其他过程的顺序是固定的.解析可以放在初始化之后,目的就是为了支持动态 ...
- 深入理解java虚拟机(1)------内存区域与内存溢出
在C++领域,关于C++的内存存储,结构等等,有一本书:深度探索C++对象模型,讲解的非常透彻. 而Java确把这一工作交给了虚拟机来处理. 我们首先来看看关于内存的问题. 1.问题: 1)java ...
- 什么是HotSpot VM & 深入理解Java虚拟机
参考 http://book.2cto.com/201306/25434.html 另外,这篇文章也是从一个系列中得出的: <深入理解Java虚拟机:JVM高级特性与最佳实践(第2版)> ...
- 【Todo】深入理解Java虚拟机 读书笔记
有一个在线系列地址 <深入理解Java虚拟机:JVM高级特性与最佳实践(第2版)> http://book.2cto.com/201306/25426.html 已经下载了这本书(60多M ...
随机推荐
- 【杂谈】从实现角度看ChannelFuture
JDK中的Future特性 在介绍Netty的ChannelFuture之前,我们先来看看JDK中的Future是如何实现的.总的来说就是任务提交的时候会使用装饰器模式,将任务包装成一个FutureT ...
- 华硕笔记本无法U盘启动,快捷键识别不了
http://www.udaxia.com/upqd/8254.html 转载于:https://www.cnblogs.com/wanglinjie/p/10507888.html
- CultureInfo 类中需要的【区域性名称】查询
2019独角兽企业重金招聘Python工程师标准>>> 提供有关特定区域性的信息(对于非托管代码开发,则称为"区域设置"). 这些信息包括区域性的名称.书写系统. ...
- vue2.0学习笔记(第八讲)(vue-cli的使用)
vue-cli相当于脚手架,可以帮助我们自动生成模板工程.其内部集成了很多的项目模板,如simple.webpack.webpack-simple等.其中webpack这个项目模板适用于大型项目的开发 ...
- 支付宝小程序云开发serverless----获取用户的user_id
支付宝小程序云开发serverless----获取用户的user_id 博客说明 文章所涉及的资料来自互联网整理和个人总结,意在于个人学习和经验汇总,如有什么地方侵权,请联系本人删除,谢谢! 开通云调 ...
- 001_python变量,if,while
Python介绍 python的出生与应用 python的创始人为吉多·范罗苏姆(Guido van Rossum).1989年的圣诞节期间,吉多·范罗苏姆(中文名字:龟叔)为了在阿姆斯特丹打发时间, ...
- puamap是什么意思
artists map 定义格式:[puamap代号 名] 相关属性: 1.FIGHT 2.SAFE 安全区域 3.DARK 4.NEEDHOLE 配合mapinfo里 x,y -> x1,y1 ...
- thrift的使用
简介 thrift 原来是facebook的rpc框架,根据数据结构和接口描述生成多种语言的接口,方便使用多种语言进行开发,详细信息这里不再赘述,下文以一个简单的代码(C++)示例来介绍使用方法. 示 ...
- 推荐算法_CIKM-2019-AnalytiCup 冠军源码解读_2
最近在为机器学习结合推荐算法的优化方法和数据来源想办法.抱着学习的态度继续解读19-AnalytiCup的冠军源码. 第一部分itemcf解读的连接:https://www.cnblogs.com/m ...
- 【Hadoop离线基础总结】日志采集框架Flume
日志采集框架Flume Flume介绍 概述 Flume是一个分布式.可靠.和高可用的海量日志采集.聚合和传输的系统.它可以采集文件,socket数据包.文件.文件夹.kafka等各种形式源数据,又可 ...