JVM复习

JVM复习提纲

jvm组成

借用Java虚拟机(JVM)面试题的图来看jvm

image.png

jvm由两个子系统两个组件组成。两个子系统分别是类加载子系统,执行引擎。两个组件是运行时数据区域,本地接口。
类加载子系统:根据给定的类名,加载进运行时数据区域的方法区中
执行引擎:执行classes的指令
本地接口:与其他编程语言交互
运行时数据区域:jvm的内存

作用:编译器把java代码变成字节码,类加载器去加载字节码到内存中,即到运行时数据区域的方法区中,然后字节码通过执行引擎变成底层的指令集,指令集交给cpu的过程中要调用到本地接口来实现整个程序的功能。

jvm内存区域

java虚拟机再执行java程序的时候会把他管理的内存划分成不同的区域,有线程私有的,有线程共享的。这里借用公众号JavaGuide的图片


jdk1.8以前

jdk1.8版本

可以看到虚拟机栈,本地方法栈,程序计数器是线程私有的。堆,方法区,直接内存是线程共享。下面一个个介绍

程序计数器

程序计数器占一块较小内存,字节码解释器工作时通过改变程序计数器的值来选取下一条要执行的字节码指令,同时每个线程有自己的程序计数器,意味着线程之间互不影响,切换线程后可以恢复到上次运行的位置。
程序计数器是唯一一个不会出现OOM的内存区域,因为他的生命周期随着线程创建而创建,结束而死亡。

虚拟机栈

虚拟机栈是线程私有的,生命周期和线程相同。描述的java方法执行的内存模型,每次方法调用的数据都是通过栈来传递。
java内存大概分为栈内存和堆内存,栈指的是虚拟机栈中的局部变量表,主要存放编译器可知的各种数据类型以及对象引用。
java虚拟机栈会出现两种错误StackOverFlowError与OutOfMemoryError。

本地方法栈

基本与虚拟机栈类似,虚拟机栈为虚拟机执行java方法,本地方法栈为虚拟机使用的native方法服务。

堆是虚拟机中占内存最大的一块,负责存放对象实例,几乎所有对象实例和数组都在这分配内存。如果某些方法中的对象引用没有被返回或者未被外面使用,就会分配内存在栈上。
java堆是垃圾收集器管理的主要区域,由于现在都采用分代垃圾收集算法,所以堆细分成新生代,老年代。


jdk7之前

可以看到jvm分为堆内存和非堆内存,非堆内存就是永久代,又称方法区。堆内存存放的是对象,同时垃圾收集器就是判断处理这些对象的。非堆内存存放的是永久代,放的是程序运行时长期存在的对象,如类的方法,常量。
JDK8的时候废除了永久代,然后在直接内存里面弄了个元空间,都是方法区的实现。

方法区

方法区是各线程共享的一个区域,存储类的常量,静态变量等。方法区与永久代的关系引用文献

《Java 虚拟机规范》只是规定了有⽅法区这么个概念和它的作⽤,并没有规定如何去实现它。那么,在不同的 JVM 上⽅法区的实现肯定是不同的了。 ⽅法区和永久代的关系很像Java 中接⼝和类的关系,类实现了接⼝,⽽永久代就是 HotSpot 虚拟机对虚拟机规范中⽅法区的⼀种实现⽅式。 也就是说,永久代是 HotSpot 的概念,⽅法区是 Java 虚拟机规范中的定义,是⼀种规范,⽽永久代是⼀种实现,⼀个是标准⼀个是实现,其他的虚拟机实现并没有永久代这⼀说法。

为什么要用元空间来代替永久代,永久代有jvm设置的固定大小,不能调整,所以经常发生空间溢出的错误,而元空间用的是直接内存,就是你机器可用内存的限制,出现错误的概率比较小。

运行时常量池

运行时常量池在方法区里面,一开始运行时常量池逻辑包括字符串常量池在永久代里面,jdk7后就把字符串常量池移到了堆中,运行池常量池则还在方法区,不过方法区从永久代变成了元空间。

堆和栈的区别

  • 栈是线程之间私有的,堆是所有线程共享的。
  • 栈的存取速度比堆快,

java类加载的过程

分为三个步骤,加载,连接,初始化。其中连接可以分为验证,准备,解析。
加载:将class文件加载进内存,并创建一个class对象。类的加载有类加载器来完成。
验证:确保加载类的信息符合规范,无安全问题。
准备:为类的静态Field分配内存,设置初始值(不是代码设置的初始值,是java虚拟机的默认初始值)
解析:将类的二进制数据中的符号引用替换成直接引用
初始化:对类的变量初始化,对static修饰的变量或者代码块进行初始化。

类加载器有 启动类加载器,扩展类加载器,系统类加载器,用户自定义类加载器

类加载的机制

双亲委托机制:首先,每个加载器都有对应的父加载器,除了启动类加载器。
类加载器收到加载的请求,不会自己立马加载,而是去把请求转给父类,如果父类还有父类,就继续转。当转到启动类加载器(即没有父类了),判断启动类加载器有没有加载过,有就加载成功,不能就回退给启动类加载器的子类,尝试是否被加载过,不能就继续回退,一直到第一个类加载器自己加载为止。
优点:防止重复加载一个类,保证数据安全。

java对象的创建过程

分为类加载检查,分配内存,把内存区域初始化零值,设置对象头,执行init方法。

类加载检查:检查new后面的参数是否能在常量池中定位到这个类的符号引用,检查是否被加载过,没有就按步骤去加载类。
分配内存:为新的对象分配内存,内存大小在第一步就已经知道了。分配方式有“指针碰撞”和“空闲列表”两种。
初始化零值:虚拟机将分配到的内存都初始化为零值。(注意:不包括对象头)
设置对象头:把一些必要信息存放到对象头中。
执行init方法:执行完new之后,已经生成了一个可用的对象了,然后要按照程序员的意愿执行init方法,就是把它设置成任意值这种,人为的初始化。

对象的访问方式

访问方式由虚拟机来实现,一般由两种,句柄访问,直接指针。

内存分配

堆内存分为新生代,老年代。新生代又分为eden区,survivor from(s0),survivor to(s1),eden区域最大。一般对象会在eden区分配,当eden没有足够空间去分配,就发起一次Minor GC(新生代垃圾收集)。大对象(需要大量连续内存空间)直接进入老年代,长期存活的对象进入老年代。每个对象都有一个age计数器,对象在survivor区每经过一次Minor GC就增加一岁,如果到了默认值(一般15),就会变成老年代。

判断对象死亡的两种方法

堆进行回收要判断对象是否已经死亡(不再被任何途径使用的对象)。
引用计数法:每个对象添加一个引用计数器,有被引用就+1,失效就-1。如果计数器为0就是不可能再被使用的了。
可达性分析算法:把名字是GC Roots的对象作为起点,通过这些起点开始往下搜索,节点走过的路径就是引用链,如果一个对象到GC Roots没有任何引用链,就代表对象不可用了,可以被回收了
图片出自JavaGuide的复习资料


可达性分析

垃圾收集算法

  • 标记-清理算法
    先标记出所有不需要回收的对象,然后把没有标记的对象都给回收了。有效率问题和回收后存在大量不连续的碎片问题。
  • 复制算法
    先把内存分为两块相同大小的内存块,每次使用都只在一个上面使用,当这块内存使用完后,回收掉不需要的对象,然后把剩下的对象复制到另一个内存上面,再把这个内存块全部清理掉,下次再使用。
  • 标记-整理算法
    先进行标记不需要回收的对象,然后把所有对象移动到另一端,然后直接清理掉边界以外的内存。
  • 分代收集算法
    根据存活周期分为不同代的对象,如新生代,老年代一样。根据每个年代的特点执行相对应的算法。如新生代使用复制算法,老年代使用标记清理,标记-整理算法。这样子就可以提高gc的效率。

四个引用

引用计数法和可达性分析算法都是判断对象是否被引用。引用又可以分为强引用,软引用,弱引用,虚引用。
强引用:大部分引用都是强引用,垃圾回收器决定不会回收强引用,即使抛出OOM错误,终止程序都不会随意回收强引用对象。可能会导致内存泄露。
在安卓中一般就是new一个对象就是强引用了。
软引用:软引用如果内存足够就不管他,如果内存不足了,就会开始回收他。只要没被回收就可以使用。
从网络上获取照片并显示时,用软引用缓存下来。下次再去网络上获取的时候就可以先判断该图片有没有被缓存,有的话就显示。
弱引用:如果垃圾回收器发现了弱引用的对象,不管内存是否充足,都会进行回收。但是垃圾回收机制优先级低,所以一般不会立马回收掉。
安卓中也可以缓存一些数据,防止内存泄露。
虚引用:如果一个对象有虚引用,和没有引用一样。任何时候都可能被回收。虚引用主要用于跟踪对象被垃圾回收的活动。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,036评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,046评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,411评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,622评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,661评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,521评论 1 304
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,288评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,200评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,644评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,837评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,953评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,673评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,281评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,889评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,011评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,119评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,901评论 2 355

推荐阅读更多精彩内容

  • 1. Java内存结构: 类加载子系统:负责从文件系统或者网络加载Class信息,加载的信息存放在一块称之方法区的...
    来往穿梭阅读 433评论 0 1
  • 1.内存模型以及分区,需要详细到每个区放什么。 java虚拟机栈:每个方法运行时都会创建一个栈帧用于存放局部变量表...
    风中追风_阅读 471评论 1 1
  • 此次JVM知识点包含以下几个部分 1.类加载机制 2.jvm运行时数据区 3.java对象内存布局 4.jvm内存...
    前程有光阅读 151评论 0 0
  • 内存和高速缓存 计算机需要读写与存储,而用户磁盘远远跟不上cpu读写的速度,所以设计了内存;然而随着硬件的高速发展...
    内拉祖睿阅读 368评论 0 0
  • 表情是什么,我认为表情就是表现出来的情绪。表情可以传达很多信息。高兴了当然就笑了,难过就哭了。两者是相互影响密不可...
    Persistenc_6aea阅读 125,038评论 2 7