JVM

简介

Jvm 系列一:Java类的加载机制
Jvm系列二:JVM内存结构 --内存泄漏与内存溢出
Jvm系列三:GC算法 垃圾收集器
Jvm系列四:jvm调优-命令篇
Jvm系列五:java GC分析
Java技术体系主要由 class文件格式 + jvm + javaApi + java框架 构成
不了解虚拟机运行的特性原理,就无法写出适合虚拟机运行和自优化的代码
虚拟机特性和调优方法
。。。

一、 Java类的加载机制

类加载机制是指:
1.将类的.class文件中的二进制数据读入到内存中,将其放在运行时数据模型的方法区中,=>保存类的数据结构
2.然后在堆区创建一个** java.lang.Class对象** => 作为对方法区中这些数据的访问入口。
3.并且向Java程序员提供了访问方法区内的数据结构的接口。

加载阶段完成后,虚拟机外部的二进制字节流就按照虚拟机所需的格式存储在方法区之中,
而且在Java堆中也创建一个 java.lang.Class类的对象,
这样便可以通过该对象访问方法区中的这些数据。

当类被加载之后,系统为之生成一个对应的Class对象
接着将会进入连接阶段,连接阶段负责把类的二进制数据合并到JRE中

================
加载.class文件的方式
本地、
网络、
专有数据库提取.class文件、
将Java源文件动态编译为.class文件
从zip,jar等归档文件中加载.class文件

参考链接 :
https://zhuanlan.zhihu.com/p/60684596
https://zhuanlan.zhihu.com/p/44670213
https://zhuanlan.zhihu.com/p/61775388 内存
https://blog.csdn.net/m0_38075425/article/details/81627349 比较详细

二、JVM内存结构

运行时数据区域:了解创建和销毁时机,有的区域随着虚拟机进程启动而存在,有的区域随着用户线程的启动和结束而创建和销毁

JVM内存结构主要有三大块: 堆内存、方法区和栈
堆内存:
a. 堆内存是JVM中最大的一块由年轻代和老年代组成1:2
b. 年轻代内存又被分成三部分(8:1:1): Eden空间、From Survivor空间、To Survivor空间
堆内存模型+GC回收
<<<<<<<<<<<<<>>>>>>>>>>>>>>>
方法区
方法区存储类信息、常量、静态变量等数据,是线程共享等区域->Non-Heap(非堆)

java虚拟机栈和本地方法栈,主要用于方法的执行

<这里应该有张图 JVM和系统调用之间的关系>

共享区

Java堆(Heap)

  1. Java Heap 是Java虚拟机管理内存中最大的一块
  2. Java堆是被所有线程共享的一块内存区域,在虚拟机启动时创建
  3. 此内存区域的唯一目的: 存放对象实例 ,几乎所有的对象实例都在这里分配内存
  4. Java堆是垃圾收集器管理的主要区域,也被称为“GC堆” -- 分代收集算法
  5. 如果在堆中没有内存完成实例分配,并且堆也无法再扩展,将会抛出OOM Error

方法区(Method Area)

  1. 方法区与Java堆一样,是各个线程共享的内存区域
  2. 它用于储存已被虚拟机加载的类信息,常量,静态变量,即时编译器编译后的代码数据
  3. 除了和Java堆一样不需要连续的内存和可以选择固定大小或者可扩展外,还可以选择不实现垃圾收集
  4. 方法区有时被称为持久代(PermGen)
    运行时常量池:类信息 + 常量池-》 编译期生成的各种字面量和符号引用
    参考链接:https://www.cnblogs.com/natian-ws/p/10749164.html
    高版本有变化
    方法的执行都伴随着线程的。
    原始类型的本地变量以及引用都存放在线程栈中。而引用关联的对象比如String,都存在在堆中

线程私有

程序计数器(Program Counter Register)

程序计数器(Program Counter Register)是一块较小的内存空间
它的作用可以看做是当前线程所执行的字节码的行号指示器---> 执行哪一行字节码
字节码解释器工作时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令
分支、循环、跳转、异常处理、线程恢复等基础功能都需要依赖这个计数器来完成

java虚拟机的多线程是通过线程轮流切换并分配处理器执行时间的方式来实现
1. 在任何一个确定的时刻,一个处理器(对于多核处理器来说是一个内核)只会执行一条线程指令  -->某个线程执行完后
2. 线程切换后能恢复到正确的执行位置,每一条线程都需要一个独立的程序计数器
3. 各条线程之间的计数器互不影响,独立储存
4. 这类内存区域为“线程私有”的内存
5. 线程执行java方法,计数器记录的是正在执行的虚拟机字节码指令的地址;
6. 如果正在执行的是Native方法,这个计数器值则为空(Undefined)
此内存区域是唯一一个在Java虚拟机规范中没有规定任何OutOfMemoryError情况的区域

JVM栈(JVM Stacks)

与程序计数器一样,Java虚拟机栈(Java Virtual Machine Stacks)也是线程私有
每一个方法从调用开始到执行完成的过程,就对应着一个栈帧在虚拟机栈里面从入栈到出栈的过程。

1. 它的生命周期与线程相同。
2. 虚拟机栈描述的是Java**方法执行**的内存模型
3. 每个方法执行的时候都会同时创建一个栈帧(Stack Frame)用于储存
    局部变量表:
      1. 存放了编译器可知的各种基本数据类型,在栈中分配多少内存空间,在编译期就已经确定了,索引访问
      stackoverflowError 
      outofmemoryError3
      2. 对象引用
      3. returnAddress类型
      4. 系统不会为局部变量赋予初始值(实例变量和类变量都会被赋予初始值)。也就是说不存在类变量那样的准备阶段。
    操作数栈:
      1. Java虚拟机的解释执行引擎被称为"基于栈的执行引擎",其中所指的栈就是指-操作数栈。
    动态链接:
      1. 由于栈帧是用于方法调用和方法执行的数据结构。所以每个栈帧都包含一个指向运行时常量池中该栈帧所属方法的引用
      2. 在class文件的常量池中有大量的符号引号。这些符号引用有一部分在类加载阶段或者第一次使用的时候就直接转化为直接引用(静态解析)。有的则在每一次运行期间转化为直接引用(动态连接)。
    方法出口等信息
4. 每一个方法被调用直至执行完成的过程,就对应一个栈帧在虚拟机出入栈的过程
本地方法栈(Native Method Stacks)
虚拟机栈为虚拟机执行Java方法(也就是字节码)服务
本地方法栈是为虚拟机使用到Native方法服务。

直接内存

使用Native函数直接直接分配堆外内存 由堆中DirectByteBuffer操纵
避免在堆内存和Native内存来回复制

JAVA 垃圾回收
  1. 垃圾回收算法

标记清除
年老代

复制算法
年轻代

标记压缩

分代收集算法
Eden => from区 => to区 => 年老区
(新生代进行回收,Minor GC,不影响老年代)
(年老满了就要进行FULL GC,也叫Major GC 包括新生代和年老代)
应该尽量减少FULL GC,因为慢 卡
导致的原因:年老代被写满,永久代被写满,显示调用System.gc()

  1. 虚拟机遇到一条New指令时的操作

检查这个指令的参数,能否在常量池中一个类的符号引用
检查这个符合引用代表的类是否已经被加载、解析、初始化
如果没有执行类加载过程
加载之后,分配内存,内存大小在编译时就已确定

  1. 根据异常信息快速判断内存溢出区域

-XX:+HeapDumpOutOfMemoryError
如果不存在内存泄漏:GcRoot引用链 - > 查看内存是否必须活着 - > 查看参数是否调大
集群同步时,导致内存溢出
使用直接内存,导致内存溢出
外部命令,导致内存溢出
不恰当数据结构,导致内存溢出

  1. 数据分析

运行日志、异常堆栈、GC日志、线程快照、堆转储快照(heapdump/prof)

cpu 寄存器 高速缓存 工作内存 主内存
内核 用户

参考链接:
https://zhuanlan.zhihu.com/p/34426768
https://www.zhihu.com/question/293352546/answer/48523571 FUllGC YGC导致的问题

参考书籍:《深入理解Java虚拟机:JVM高级特性与最佳事件》-周志明

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

推荐阅读更多精彩内容

  • 工作之余,想总结一下JVM相关知识。 Java运行时数据区: Java虚拟机在执行Java程序的过程中会将其管理的...
    Huang远阅读 635评论 0 2
  • http://www.cnblogs.com/angeldevil/p/3801189.html值得一看 Clas...
    snail_knight阅读 1,423评论 1 0
  • 内存溢出和内存泄漏的区别 内存溢出:out of memory,是指程序在申请内存时,没有足够的内存空间供其使用,...
    Aimerwhy阅读 741评论 0 1
  • 原文阅读 前言 这段时间懈怠了,罪过! 最近看到有同事也开始用上了微信公众号写博客了,挺好的~给他们点赞,这博客我...
    码农戏码阅读 5,962评论 2 31
  • 这篇文章是我之前翻阅了不少的书籍以及从网络上收集的一些资料的整理,因此不免有一些不准确的地方,同时不同JDK版本的...
    高广超阅读 15,599评论 3 83