jvm学习006 jvm内存结构分配
主要内容如下:
- JVM启动流程
- JVM基本结构
- 内存模型
- 编译和解释运行的概念
一、JVM启动流程:

JVM启动时,是由java命令/javaw命令来启动的。
二、JVM基本结构:
JVM基本结构图:

《深入理解Java虚拟机(第二版)》中的描述是下面这个样子的:

Java中的内存分配:
Java程序在运行时,需要在内存中的分配空间。为了提高运算效率,就对数据进行了不同空间的划分,因为每一片区域都有特定的处理数据方式和内存管理方式。
具体划分为如下5个内存空间:(非常重要)
- 栈:存放局部变量
- 堆:存放所有new出来的东西
- 方法区:被虚拟机加载的类信息、常量、静态常量等。
- 程序计数器(和系统相关)
- 本地方法栈
1、程序计数器:
每个线程拥有一个PC寄存器
在线程创建时创建
指向下一条指令的地址
执行本地方法时,PC的值为undefined
2、方法区:
保存装载的类信息
类型的常量池
字段,方法信息
方法字节码
通常和永久区(Perm)关联在一起
3、堆内存:
和程序开发密切相关
应用系统对象都保存在Java堆中
所有线程共享Java堆
对分代GC来说,堆也是分代的
GC管理的主要区域
现在的GC基本都采用分代收集算法,如果是分代的,那么堆也是分代的。如果堆是分代的,那堆空间应该是下面这个样子:

上图是堆的基本结构,在之后的文章中再进行详解。
4、栈内存:
- 线程私有,生命周期和线程相同
- 栈由一系列帧组成(因此Java栈也叫做帧栈)
- 帧保存一个方法的局部变量、操作数栈、常量池指针
- 每一次方法调用创建一个帧,并压栈
解释:
Java虚拟机栈描述的是Java方法执行的内存模型:每个方法被调用的时候都会创建一个栈帧,用于存储局部变量表、操作栈、动态链接、方法出口等信息。每一个方法被调用直至执行完成的过程就对应着一个栈帧在虚拟机中从入栈到出栈的过程。
在Java虚拟机规范中,对这个区域规定了两种异常情况:
(1)如果线程请求的栈深度太深,超出了虚拟机所允许的深度,就会出现StackOverFlowError(比如无限递归。因为每一层栈帧都占用一定空间,而 Xss 规定了栈的最大空间,超出这个值就会报错)
(2)虚拟机栈可以动态扩展,如果扩展到无法申请足够的内存空间,会出现OOM
4.1 Java栈之局部变量表:包含参数和局部变量
局部变量表存放了基本数据类型、对象引用和returnAddress类型(指向一条字节码指令的地址)。其中64位长度的long和double类型的数据会占用2个局部变量空间(slot),其余数据类型只占用1个。局部变量表所需的内存空间在编译期间完成分配。
例如,我写出下面这段代码:

1 package test03;
2
3 /**
4 * Created by smyhvae on 2015/8/15.
5 */
6 public class StackDemo {
7
8 //静态方法
9 public static int runStatic(int i, long l, float f, Object o, byte b) {
10 return 0;
11 }
12
13 //实例方法
14 public int runInstance(char c, short s, boolean b) {
15 return 0;
16 }
17
18 }

上方代码中,静态方法有6个形参,实例方法有3个形参。其对应的局部变量表如下:

上方表格中,静态方法和实例方法对应的局部变量表基本类似。但有以下区别:实例方法的表中,第一个位置存放的是当前对象的引用。
4、2 Java栈之函数调用组成栈帧:
方法每次被调用的时候都会创建一个栈帧,例如下面这个方法:
public static int runStatic(int i,long l,float f,Object o ,byte b){
return runStatic(i,l,f,o,b);
}
当它每次被调用的时候,都会创建一个帧,方法调用结束后,帧出栈。如下图所示:

4.3 Java栈之操作数栈
Java没有寄存器,所有参数传递都是使用操作数栈
例如下面这段代码:
public static int add(int a,int b){
int c=0;
c=a+b;
return c;
}
压栈的步骤如下:
0: iconst_0 // 0压栈
1: istore_2 // 弹出int,存放于局部变量2
2: iload_0 // 把局部变量0压栈
3: iload_1 // 局部变量1压栈
4: iadd //弹出2个变量,求和,结果压栈
5: istore_2 //弹出结果,放于局部变量2
6: iload_2 //局部变量2压栈
7: ireturn //返回
如果计算100+98的值,那么操作数栈的变化如下图所示:

4.4 Java栈之栈上分配:
小对象(一般几十个bytes),在没有逃逸的情况下,可以直接分配在栈上
直接分配在栈上,可以自动回收,减轻GC压力
大对象或者逃逸对象无法栈上分配
栈、堆、方法区交互:


三、内存模型:
每一个线程有一个工作内存。工作内存和主存独立。工作内存存放主存中变量的值的拷贝。

当数据从主内存复制到工作存储时,必须出现两个动作:第一,由主内存执行的读(read)操作;第二,由工作内存执行的相应的load操作;当数据从工作内存拷贝到主内存时,也出现两个操作:第一个,由工作内存执行的存储(store)操作;第二,由主内存执行的相应的写(write)操作。
每一个操作都是原子的,即执行期间不会被中断
对于普通变量,一个线程中更新的值,不能马上反应在其他变量中。如果需要在其他线程中立即可见,需要使用volatile关键字作为标识。

1、可见性:
一个线程修改了变量,其他线程可以立即知道
保证可见性的方法:
volatile
synchronized (unlock之前,写变量值回主存)
final(一旦初始化完成,其他线程就可见)
2、有序性:
在本线程内,操作都是有序的
在线程外观察,操作都是无序的。(指令重排 或 主内存同步延时)
3、指令重排:

指令重排:破坏了线程间的有序性:

指令重排:保证有序性的方法:

指令重排的基本原则:
程序顺序原则:一个线程内保证语义的串行性
volatile规则:volatile变量的写,先发生于读
锁规则:解锁(unlock)必然发生在随后的加锁(lock)前
传递性:A先于B,B先于C 那么A必然先于C
线程的start方法先于它的每一个动作
线程的所有操作先于线程的终结(Thread.join())
线程的中断(interrupt())先于被中断线程的代码
对象的构造函数执行结束先于finalize()方法
四、解释运行和编译运行的概念:
解释运行:
解释执行以解释方式运行字节码
解释执行的意思是:读一句执行一句
编译运行(JIT):
将字节码编译成机器码
直接执行机器码
运行时编译
编译后性能有数量级的提升
编译运行的性能优于解释运行。
转自:http://www.cnblogs.com/smyhvae/p/4748392.htm
jvm学习006 jvm内存结构分配的更多相关文章
- JVM学习01:内存结构
JVM学习01:内存结构 写在前面:本系列分享主要参考资料是 周志明老师的<深入理解Java虚拟机>第二版. 内存结构知识要点Xmind梳理 案例分析 分析1 package com.h ...
- JVM学习总结一——内存模型
JVM是java知识体系的基石之一,任何一个java程序的运行,都要借助于他.或许对于我这种初级程序员而言,工作中很少有必要刻意去关注JVM,然而如果能对这块知识有所了解,就能够更清晰的明白程序的运行 ...
- JVM(一)内存结构
今日开篇 什么是JVM 定义 Java Virtual Machine,JAVA程序的运行环境(JAVA二进制字节码的运行环境) 好处 一次编写,到处运行 自动内存管理,垃圾回收机制 数组下标越界检查 ...
- JVM体系结构-----深入理解内存结构
一.概述 内存在计算机中占据着至关重要的地位,任何运行时的程序或者数据都需要依靠内存作为存储介质,否则程序将无法正常运行.与C和C++相比,使用Java语言编写的程序并不需要显示的为每一个对象编写对应 ...
- jvm比较详尽的内存结构
JVM内存结构 2012-09-17 15:27:59 分类: Java 本文转自:http://www.blogjava.net/nkjava/archive/2012/03/14/371831. ...
- JVM学习笔记-JVM模型
JVM学习笔记 == 标签(空格分隔): jvm 学习笔记全部来自于<深入理解java虚拟机>总结 jvm内存示意图 虚拟机栈(Java Virtual Machine Stacks): ...
- JVM学习总结四——内存分配策略
之前几篇我们介绍了jvm的内存模型以及垃圾回收机制,而本篇我们将介绍几个JVM中对象在分配内存是应该遵循的策略.毕竟,想要去优化程序,不仅要考虑垃圾回收的过程,还要从对象内存分配的角度减少gc的代价. ...
- JVM学习心得—JVM内存模型(个人整理,请勿转载)
一.运行时数据区域 线程私有的:程序计数器+虚拟机栈+本地方法栈 线程共享的:堆+方法区(运行时常量池)+直接内存(非运行时数据区的一部分) *JDK1.8后将方法区废除,新增元空间. 1.1 程序计 ...
- JVM学习记录-Java内存模型(一)
前言 Java虚拟机规范中定义了一种Java的内存模型,即Java Memoory Model(简称JMM),用来实现让Java程序在各个平台下都能达到一致的内存访问效果.JVM是整个虚拟机,JMM模 ...
随机推荐
- 数据库插入数据失败,log提示不能将值 NULL 插入列 'id'
已经记不住具体的log信息了,意思就是ID如果没有设置为自增长的情况下就不能插入数据,而建表时ID字段是设置为"not null",所以就不能顺利插入数据. 解决方法有两种: ①建 ...
- VR全景智慧城市--2017年VR项目加盟将是一个机遇
全景智慧城市项目是河南艺境空间文化传播有限公司自主开发的国内第一家商业全景平台, 旨在构建全景城市,实现智慧生活,让人们随时随地身临其境拥有全世界,享受快捷.真实.趣味.优质生活. 以VR虚拟现实技术 ...
- Docker手动配置Lamp镜像
自从接了学长布置的任务,自学Docker也学了很久了,先整一个Lamp出来吧 在Docker Hub上找了很多Lamp的镜像 网上都说tutum的镜像做的还是不错的 试试 折腾了一上午无果... 算了 ...
- 小K的H5之旅-CSS基础(一)
一.什么是CSS W3C标准中,倡导有3:其一为内容与表现分离,其二为内容与行为分离,其三为内容结构的语义化.其倡导中第一条的"表现"指的便可以说是CSS.CSS全称Cascadi ...
- 初入计算机图形学——BVH结构的实现
摘要: 本人水平有限,若有错误也请指正~ 光线追踪作为全局光照解决方案的一个重要思想,其与场景大量三角形的求交效率高低直接影响最终算法的速度,典型的一些渲染器都采用二叉树来将场景进行划分,最近自己实现 ...
- java数据结构(二叉树)
Node节点: public class Node { public long data; public String sData; public Node leftChild; public Nod ...
- unity3D:游戏分解之曲线
一提到曲线,很多新手就头疼了,包括我.查了很多资料,终于有个大概的了解.想深入了解曲线原理的,推荐一个链接http://www.cnblogs.com/jay-dong/archive/2012/09 ...
- cpp(第十四章)
1.类的静态成员变量.静态常整型(static const int)变量可以直接在类声明中初始化,静态常变量(static const )需要在类定义文件中初始化, 常变量(const )则在构造函数 ...
- Copy_on_write的简单实现
Copy_on_write即写时复制,它的原理是通过引用计数来实现的. 即在分配空间时多分配额外的空间,用来记录有多少个指针指向该空间.当有新的指针指向该空间,引用计数则加一,当要释放该空间时,引用计 ...
- Linux上的防病毒软件ClamAV
Clam AntiVirus(ClamAV)是免费而且开放源代码的防毒软件,软件与病毒码的更新皆由社群免费发布.目前ClamAV主要是使用在由Linux.FreeBSD等Unix-like系统架设的邮 ...