一、JAVA程序执行流程

JAVA程序执行的基本流程(基于HotSpot):

图1

二、内存模块划分

2.1:程序计数器

程序计数器是一块较小的内存空间,是当前线程执行字节码的行号指示器,字节码解释器就是通过改变这个计数器的值来获取下一条需要执行的字节码指令,其中分支、循环、跳转和异常处理,线程恢复等基础功能均需要依赖该计数器完成。由于jvm的多线程是通过线程轮流切换并分配CPU执行时间的方式实现,在任何时刻,一个CPU都只会执行其中一条线程里的指令,为了使线程发生切换后可以顺利的定位到上次发生切换时的执行位置,每个线程都有一个独立的程序计数器,每条线程的计数器相互独立,这块存储区域被称为线程私有内存。

2.2:方法区

也是线程共享的一块区域,这块区域主要用来存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据,HotSpot虚拟机实现该区域时采用堆的一块区域实现,目的是为了让GC分代收集扩展至方法区(比如类卸载时是需要GC参与的),因此在堆空间里划分出一个代来存储方法区里的内容,这块区域通常被称作“永久代”,该块区域大小通过-XX:MaxPermSize来设置(因此可能会出现OOM的情况),不过需要说明的是,J8已经没有这块区域了,而且J7的时候已经将常量池由该块区域转移到实际的堆内存里了(实验证明,J7和J8的时候,常量池已经被存进了实际的堆内存,但区别是J7的类信息等还放在永久代中)。J8有了元数据存储,已经彻底去除了永久代的概念,具体了解:Java8内存划分

2.3:堆

jvm管理的最大一块区域,jvm启动时创建,用来存放对象实例,几乎所有的对象都在这里分配内存,通过-Xmx-Xms控制其大小。这块区域是GC管理的主要区域,从内存回收角度来看,现在的内存回收基本都采用分代收集算法,所以该区域还可以细分(如图1堆空间细分),进一步划分的目的是为了更好的回收内存或更快的分配内存。这里列一下例子里用到的参数(也是比较常用的参数):

名称 含义
-xms 堆初始化大小
-xmx 堆最大大小(一般来说,-xms和-xmx设置大小一致,以避免每次垃圾回收完成后JVM重新分配内存)
-xmn 新生代大小(结合图1理解),这里需要提一下-XX:newSize、-XX:MaxnewSize这俩参数,第一个是指新生代初始大小,第二个是指新生代最大大小,同样为了避免JVM重新分配内存,这俩数值一般设置为一样的,所以jdk4出来了-xmn,一个配置,可以对上述俩参数同时生效
-XX:NewRatio 新生代(Eden+2Survivors)与老年代的大小比值,如果值为2,则新生代:老年代=1:2(如果设置了-xmn指定了新生代大小,则无需设置此项,两个都设置,只生效一个)
-XX:SurvivorRatio 新生代中,Eden区与两个Survivor的大小比值,如果设置为4,则eden:survivor1:survivor2 = 4:1:1)
-xss 栈大小,一般默认128k,如果调用栈不是很深(比如很深的递归程序),保持默认即可

表1

2.3.1:堆配置详解

现在让我们把图1中的“堆空间细分”部分放大,结合下面的配置信息和表1中的含义(-Xss和永久代不会体现在图里),来用图说明下:

配置1:-Xmx3072m  -Xms3072m  -Xmn2g -XX:SurvivorRatio=4  -Xss128k

上面的配置表示堆区总大小为3550M,新生代大小为2G(2048M,这里只是说明问题才配置这么大,实际生产中,新生代要小于老年代),新生代Eden区和两个Survivor区的比例为4:1:1,用图来直观的表达一下这个配置:

图2

配置2:-Xmx3072m  -Xms3072m  -XX:NewRatio=2 -XX:SurvivorRatio=4  -Xss128k

上面的配置表示堆区总大小为3550m,新生代:老年代=1:2(HotSpot默认),新生代eden区和两个survivor区的比例为4:1:1,用图来直观的表达一下这个配置:

图3

2.4:虚拟机栈

也就是常说的栈,线程私有,生命周期与线程相同,虚拟机栈用来描述java方法(java method)执行的内存模型,每个方法执行时都会创建一个栈帧,用于存储局部变量表、操作数栈、动态链接、方法出口等信息,一个方法的调用到其完成调用对应一个栈帧在虚拟机的入栈到出栈。

局部变量表里存放着编译期可知的基本数据类型、对象引用Reference(可能是指向实例对象地址的一个引用指针,也可能是代表实例对象的一个句柄)、以及returnAddress(指向一条字节码的执行命令的地址)。在此区域,如果线程的请求深度大于虚拟机允许的深度,将会抛出StackOverFlowError异常,这个可以通过一个无限制递归或者递归深度设置一个很大的数来证明:


public class Recursion { public static int i = 0; public static void main(String[] args) {
Recursion t = new Recursion();
t.recursion();
System.out.println("程序正常结束~");
} public void recursion(){
i++;
if(i > 30000){ //这里做适当调整,减小则不报栈溢出异常,扩大(比如这里的3w)就会报栈溢出
return;
}
recursion();
}
}

看注释那里调整即可证明。栈大小通过-Xss参数来调整,需要注意的是,这个参数是对每个线程生效的(栈帧),一般情况下,这个设置的值越小,支持创建的线程数就越多(并非可以无限多,最终受操作系统限制,操作系统针对每个进程也有个最大线程数的限制),栈里存储的大部分数据,都会随着栈帧的结束(即method调用完成)而被回收,所以一般递归更容易造成栈溢出问题。

2.5:本地方法栈

意义类似虚拟机栈,只不过本地方法栈服务于本地native方法调用(JNI),我们常用的虚拟机HotSpot已将该区和虚拟机栈做了合并。

JVM基础回顾记录(一):JVM的内存模型的更多相关文章

  1. JVM基础回顾记录(二):垃圾收集

    垃圾收集流程&HotSpot对该流程的实现方式 上一篇介绍了jvm的内存模型,本篇将介绍虚拟机中最为复杂的一部分:垃圾收集,本篇会从垃圾回收前的准备工作到后面的收集阶段的方式以及HotSpot ...

  2. JVM基础学习(二):内存分配策略与垃圾收集技术

    Java与C++之间有一堵由内存动态分配和垃圾收集技术所围成的高墙,墙外面的人想进去,墙里面的人却想出来 垃圾收集概述 Java内存模型中的堆和方法区是垃圾收集技术所需要关注的终点,因为其他的区域会跟 ...

  3. JVM基础:深入学习JVM堆与JVM栈

    转自:http://developer.51cto.com/art/201009/227812.htm JVM栈解决程序的运行问题,即程序如何执行,或者说如何处理数据;JVM堆解决的是数据存储的问题, ...

  4. JVM虚拟机(五):JDK8内存模型—消失的PermGen

    一.JVM 内存模型 根据 JVM 规范,JVM 内存共分为虚拟机栈.堆.方法区.程序计数器.本地方法栈五个部分. 1.虚拟机栈: 每个线程有一个私有的栈,随着线程的创建而创建.栈里面存着的是一种叫“ ...

  5. JVM学习(3)——总结Java内存模型

    俗话说,自己写的代码,6个月后也是别人的代码……复习!复习!复习!涉及到的知识点总结如下: 为什么学习Java的内存模式 缓存一致性问题 什么是内存模型 JMM(Java Memory Model)简 ...

  6. JVM学习(3)——总结Java内存模型---转载自http://www.cnblogs.com/kubixuesheng/p/5202556.html

    俗话说,自己写的代码,6个月后也是别人的代码……复习!复习!复习!涉及到的知识点总结如下: 为什么学习Java的内存模式 缓存一致性问题 什么是内存模型 JMM(Java Memory Model)简 ...

  7. JVM基础知识2 垃圾收集器与内存分配策略

    如何判断堆中的哪些对象可以被回收 主流的程序语言都是使用根搜索算法(GC Roots Tracing)判定对象是否存活 基本思路是:通过一系列名为“GC Roots”的对象作为起点,从这些节点开始向下 ...

  8. JVM基础系列第3讲:到底什么是虚拟机?

    我们都知道在 Windows 系统上一个软件包装包是 exe 后缀的,而这个软件包在苹果的 Mac OSX 系统上是无法安装的.类似地,Mac OSX 系统上软件安装包则是 dmg 后缀,同样无法在 ...

  9. JVM基础系列第2讲:Java 虚拟机的历史

    说起 Java 虚拟机,许多人就会将其与 HotSpot 虚拟机等同看待.但实际上 Java 虚拟机除了 HotSpot 之外,还有 Sun Classic VM.Exact VM.BEA JRock ...

随机推荐

  1. BZOJ 3033 太鼓达人(DFS+欧拉回路)

    Description 七夕祭上,Vani牵着cl的手,在明亮的灯光和欢乐的气氛中愉快地穿行.这时,在前面忽然出现了一台太鼓达人机台,而在机台前坐着的是刚刚被精英队伍成员XLk.Poet_shy和ly ...

  2. Jomoo的模板

    目录 1 杂类算法 1.1 快读模板 1.2 O(1) int64 乘法 2 图论算法 2.1 树类 - Trie 2.2 树类 - 并查集(NB version) 2.3 树类 - LCA 2.4 ...

  3. Zabbix与ELK整合实现对日志数据的实时监控

    4.2.zabbix平台配置日志告警 一. ELK与zabbix有什么关系? ELK大家应该比较熟悉了,zabbix应该也不陌生,那么将ELK和zabbix放到一起的话,可能大家就有疑问了?这两个放到 ...

  4. [vue]数据来源

    1.组件data函数return的数据 作用域是组件本身 可以在模板template及计算属性computed和方法methods中使用 2.父传子,props数据 来自父级:可以是写死的,或者是来自 ...

  5. Python发送邮件以及对其封装

    对Python发送邮件进行封装 Python发送邮件分为四步 连接到smtp服务器 登陆smtp服务器 准备邮件 发送邮件 导入所需要的包 import smtplib from email.mime ...

  6. 【Eureka】服务端和客户端

    [Eureka]服务端和客户端 转载:https://www.cnblogs.com/yangchongxing/p/10778357.html Eureka服务端 1.添加依赖 <?xml v ...

  7. 4种MySQL分页查询优化的方法,你知道几个?

    前言 当需要从数据库查询的表有上万条记录的时候,一次性查询所有结果会变得很慢,特别是随着数据量的增加特别明显,这时需要使用分页查询.对于数据库分页查询,也有很多种方法和优化的点.下面简单说一下我知道的 ...

  8. python学习-文件创建读取

    # 文件创建 # 读写# 文件存在?不存在?在操作系统上# 读 read r 写 write w# 打开一个文件# fs = open("xiaojian.txt",encodin ...

  9. sql为什么用0,1表示男女?在sql语句里转好还是在页面转好?

    转化语句:SELECT CASE `user_gender` WHEN '1' THEN '男' WHEN '0' THEN '未知'ELSE '女' END AS gender FROM `info ...

  10. [ASP.NET Core 3框架揭秘] 文件系统[4]:程序集内嵌文件系统

    一个物理文件可以直接作为资源内嵌到编译生成的程序集中.借助于EmbeddedFileProvider,我们可以采用统一的编程方式来读取内嵌的资源文件,该类型定义在 "Microsoft.Ex ...