目录

栈上分配

逃逸分析

标量替换

内存溢出和内存泄露区别

跨平台原理

JVM的运行机制

编译原理

冯诺依曼模型

类文件Class结构

对象的创建

对象的结构

内存分配策略

类加载器

类加载过程

双亲委派机制

对象的访问

什么是安全点

编译型和解释性

什么时候垃圾回收

实例化一个对象的过程

大端存储和小端存储

loadClass和forName的区别

-Xms和-Xmx为什么设置一样

tomcat怎么设置jvm参数

调优参数

各版本垃圾收集器

JVM性能调优与底层原理分析(学习笔记)

JVM内存模型

判断垃圾以及回收垃圾和四大引用

四种垃圾收集算法和垃圾收集器记忆技巧

深入理解JVM-ZGC垃圾收集器

full gc过于频繁该怎么解决

怎么合理设置JVM内存分配的比例

CMS与三色标记算法

使用JProfiler分析dump文件定位OOM

使用JVisualVM分析dump文件定位OOM

JVM常用命令汇总

JVM的GC日志分析

java获取jvm是32位或64位

System.gc()和Runtime.getRuntime().gc()区别

栈上分配

栈上分配主要是指在Java程序的执行过程中,在方法体中声明的变量以及创建的对象,将直接从该线程所使用的栈中分配空间。一般而言,创建对象都是从堆中来分配的,这里是指在栈上来分配空间给新创建的对象。

逃逸分析

逃逸是指在某个方法之内创建的对象,除了在方法体之内被引用之外,还在方法体之外被其它变量引用到;这样带来的后果是在该方法执行完毕之后,该方法中创建的对象将无法被GC回收,由于其被其它变量引用。正常的方法调用中,方法体中创建的对象将在执行完毕之后,将回收其中创建的对象;故由于无法回收,即成为逃逸。

标量替换

内存溢出和内存泄露区别

内存溢出(out of memory):指程序在申请内存时,没有足够的内存空间供其使用,出现out of memory;比如申请了一个integer,但它存了long才能存下的数,那就是内存溢出。
内存泄露(memory leak):是指程序在申请内存后,无法释放已申请的内存空间,一次内存泄露危害可以忽略,但内存泄露堆积后果很严重,无论多少内存,迟早会被占光。
memory leak会最终会导致out of memory!
内存溢出就是你要求分配的内存超出了系统能给你的,系统不能满足需求,于是产生溢出。
 例子如下:
  内存溢出,就是说,你向系统申请了装10个橘子的篮子(内存)并拿到了,但你却用它来装10个苹果,从而超出其最大能够容纳的范围,于是产生溢出;内存泄漏,就是说系统的篮子(内存)是有限的,而你申请了一个篮子,拿到之后没有归还(忘记还了或是丢了),于是造成一次内存泄漏。在你需要用篮子的时候,又去申请,如此反复,最终系统的篮子无法满足你的需求,最终会由内存泄漏造成内存溢出。

跨平台原理

所谓跨平台性,是指java语言编写的程序,一次编译后,可以在多个系统平台上运行。
实现原理:Java程序是通过java虚拟机在系统平台上运行的,只要该系统可以安装相应的java虚拟机,该系统就可以运行java程序。

JVM的运行机制

.java--javac编译-->.class->类加载子系统->运行时数据区->执行引擎(即时编译器/垃圾回收器)->本地接口库->本地方法库

-本地接口库调用本地方法库完成具体的指令操作。
-执行引擎:任务就是将字节码指令解释/编译为对应平台上的本地机器指令才可以。简单来说,JVM 中的执行引擎充当了将高级语言翻译为机器语言的译者。
-本地接口库:作用是融合不同的编程语言为 Java 所用。
-本地方法库:存储的是本地方法的实现方法。

JIT是编译器和解释器的组合,编译器和解释器的工作都是将程序员的源代码翻译成可执行的机器代码,要么一次性翻译(编译器),要么逐行解释并运行(解释器)。编译器可以扮演一个很好的翻译器,因为它可以使代码快速运行;然而,它必须先将源代码翻译成二进制文件,然后才能执行。当我们只有机器代码工作时,从源代码中调试一些问题就很痛苦。另一方面,解释器可以在运行时直接执行代码片段,这意味着如果有问题,它可以在运行时保存执行代码被调用的上下文(context)。然而,解释器多次重新翻译代码,这使它变得缓慢和低效。那么,JIT 在这方面的作用是什么呢?首先,JIT 像它的其中一位父母——意思是,开始的时候像解释器(Interpreter),在被调用的时候执行并重复运行代码。然而,如果 JIT 发现代码被多次调用并循环引用,它的行为就像另外一位父母:编译器(Compiler)。JIT 的行为像解释器(Interpreter),直到它注意到正在做一堆重复的工作。这点上,它更像编译器(Compiler),并将通过直接编译来优化重复代码。这使得 JIT 能够从它的父母中吸取精华。虽然它是从解释源文本开始的,但是它以一种特殊的方式进行。JIT 必须在解释的过程中仔细观察它所运行的内联代码。

编译原理

Person.java -> 词法分析器 -> tokens流 -> 语法分析器 -> 语法树/抽象语法树 -> 语义分析器-> 注解抽象语法树 -> 字节码生成器 -> Person.class文件

冯诺依曼模型

输入设备/输出设备/存储器/运算器/控制器

类文件Class结构

ClassFile {
    u4             magic; //Class 文件的标志
    u2             minor_version;//Class 的小版本号
    u2             major_version;//Class 的大版本号
    u2             constant_pool_count;//常量池的数量
    cp_info        constant_pool[constant_pool_count-1];//常量池
    u2             access_flags;//Class 的访问标记
    u2             this_class;//当前类
    u2             super_class;//父类
    u2             interfaces_count;//接口
    u2             interfaces[interfaces_count];//一个类可以实现多个接口
    u2             fields_count;//Class 文件的字段属性
    field_info     fields[fields_count];//一个类会可以有个字段
    u2             methods_count;//Class 文件的方法数量
    method_info    methods[methods_count];//一个类可以有个多个方法
    u2             attributes_count;//此类的属性表中的属性数
    attribute_info attributes[attributes_count];//属性表集合
}

对象的创建

类加载检查

虚拟机遇到一条new指令时,先根据new的参数在常量池中定位一个符号引用,没有找到引用,则执行的类的加载、验证、初始化

分配内存

指针碰撞:
用过的内存全部整合到一边,没有用过的内存放在另一边,中间有一个分界值指针,分配内存的时候只需要向着没用过的内存方向将该指针移动对象内存大小位置即可.
空闲列表:
虚拟机会维护一个列表,该列表中会记录哪些内存块是可用的,在分配的时候,找一块足够大的内存块来划分给对象实例,最后更新列表记录.

内存分配并发问题

CAS+失败重试:
CAS是乐观锁的一种实现方式。所谓乐观锁就是,每次不加锁而是假设没有冲突而去完成某项操作,如果因为冲突失败就重试,直到成功为止。虚拟机采用CAS配上失败重试的方式保证更新操作的原子性。
TLAB:
为每一个线程预先在Eden区分配一块儿内存,JVM在给线程中的对象分配内存时,首先在TLAB分配,当对象大于TLAB中的剩余内存或TLAB的内存已用尽时,再采用上述的CAS进行内存分配

初始化零值

内存分配完成后,虚拟机需要将分配到的内存空间都初始化为零值(不包括对象头)这一步操作保证了对象的实例字段在Java代码中可以不赋初始值就直接使用,程序能访问到这些字段的数据类型所对应的零值

设置对象头

初始化零值完成之后,虚拟机要对对象进行必要的设置,例如这个对象是那个类的实例、如何才能找到类的元数据信息、对象的哈希码、对象的GC分代年龄等信息。这些信息存放在对象头中。另外,根据虚拟机当前运行状态的不同,如是否启用偏向锁等,对象头会有不同的设置方式

执行 init 方法

在上面工作都完成之后,从虚拟机的视角来看,一个新的对象已经产生了,但从 Java 程序的视角来看,对象创建才刚开始,<init> 方法还没有执行,所有的字段都还为零。所以一般来说,执行 new 指令之后会接着执行 <init> 方法,把对象按照程序员的意愿进行初始化,这样一个真正可用的对象才算完全产生出来。

对象的结构

对象头(Header):
1.markword:用于存储对象自身的运行时数据,如哈希码(HashCode)、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID、偏向时间戳等,这部分数据的长度在32位和64位的虚拟机(未开启压缩指针)中分别为32bit和64bit
2.klass:klass类型指针,即对象指向它的类元数据的指针,虚拟机通过这个指针来确定这个对象是哪个类的实例.
3.数组长度(只有数组对象有):如果对象是一个数组,那在对象头中还必须有一块数据用于记录数组长度
实例数据:
实例数据部分是对象真正存储的有效信息,也是在程序代码中所定义的各种类型的字段内容。无论是从父类继承下来的,还是在子类中定义的,都需要记录起来。
对齐填充:
第三部分对齐填充并不是必然存在的,也没有特别的含义,它仅仅起着占位符的作用。由于HotSpotVM的自动内存管理系统要求对象起始地址必须是8字节的整数倍,换句话说,就是对象的大小必须是8字节的整数倍。而对象头部分正好是8字节的倍数(1倍或者2倍)因此,当对象实例数据部分没有对齐时,就需要通过对齐填充来补全。

内存分配策略

-对象优先分配在Eden区:大多数情况下,对象在新生代中的Eden区分配,当Eden区没有足够空间进行分配时,虚拟机将发生一次Minor GC。
-大对象直接进入老年代:大对象是指,需要大量连续内存空间的Java对象,虚拟机提供了相关参数调整大小。
-长期存活的对象进入老年代:每次Minor GC,年龄就增加一岁,默认15岁,进入老年代,也可以通过参数调整。
-动态对象年龄判定:如果在Survivor空间中相同年龄所有对象大小的总和大小大于Survivor空间的一半,年龄大于或等于该年龄的对象就可以直接进入老年代。
-空间分配担保:在发生Minor GC前,虚拟机会检查老年代的最大可用连续空间是否大于新生代所有对象的总空间,如果大于,则此次Minor GC是安全的.如果小于,则虚拟机会查看HandlePromotionFailure设置值是否允许担保失败。如果HandlePromotionFailure=true,那么会继续检查老年代最大可用连续空间是否大于历次晋升到老年代的对象的平均大小,如果大于,则尝试进行一次Minor GC,但这次Minor GC依然是有风险的;如果小于或者HandlePromotionFailure=false,则改为进行一次Full GC。

类加载器

类加载器负责加载class文件加载到JVM内存
Bootstrap ClassLoader(启动类加载器C++)负责加载$JAVA_HOME/jre/lib/rt.jar下面的类
Extension ClassLoader(扩展类加载器Java)负责加载$JAVA_HOME/jre/lib/ext/*.jar下面的类
System ClassLoader(系统类加载器Java)负责加载当前应用classpath下面所有类

隐式加载:使用new +构造方法时,隐式的调用类加载器,加载对应的类到JVM中,是最常见的类加载方式

显式加载:使用loadClass()、forName()等方法显式的加载需要的类,对于显式加载这种类加载方式来讲, 当我们获取到了Class对象后,需要调用Class对象的newInstance()方法来生成对象的实例

手写自己的类加载器

类加载过程

加载:
读取class文件并把class文件描述成Class对象的过程。
1.根据类的全限定名获取类的二进制字节流
2.二进制字节流代表的静态结构转化为方法区运行时的数据结构
3.内存创建Class对象,作为方法区这个类的各种访问入口
验证:
验证Class文件是否符合虚拟机的规范
准备:
方法区中的类变量赋初值和分配内存空间
解析:
JVM把常量池内的符号引用转为直接引用
初始化:
初始化是为类的静态变量赋予正确的初始值,准备阶段和初始化阶段看似有点矛盾,其实是不矛盾的,如果类中有语句:private static int a = 10,它的执行过程是这样的,首先字节码文件被加载到内存后,先进行链接的验证这一步骤,验证通过后准备阶段,给a分配内存,因为变量a是static的,所以此时a等于int类型的默认初始值0,即a=0,然后到解析(后面在说),到初始化这一步骤时,才把a的真正的值10赋给a,此时a=10.
必须初始化
1.必须初始化(new,getstatic,putstatic,invokestatic)
2.反射reflect包的使用
3.初始化一个类,如果其父类还未初始化,则先触发该父类的初始化。
4.当虚拟机启动时,用户需要定义一个要执行的主类,虚拟机会先初始化这个类。
5.MethodHandle和VarHandle可以看作是轻量级的反射调用机制,而要想使用这2个调用,就必须先使用findStaticVarHandle来初始化要调用的类。

双亲委派机制

其工作原理的是,如果一个类加载器收到了类加载请求,它并不会自己先去加载,而是把这个请求委托给父类的加载器去执行,如果父类加载器还存在其父类加载器,则进一步向上委托,依次递归,请求最终将到达顶层的启动类加载器,如果父类加载器可以完成类加载任务,就成功返回,倘若父类加载器无法完成此加载任务,子加载器才会尝试自己去加载,这就是双亲委派模式,即每个儿子都很懒,每次有活就丢给父亲去干,直到父亲说这件事我也干不了时,儿子自己才想办法去完成。
双亲委派机制的优势:
1.避免类的重复加载
2.防止核心API库被随意篡改

缓存机制:对于一个类加载器实例来说,相同全名的类只加载一次,即loadClass方法不会被重复调用
打破双亲委派:SPI/OSGI

对象的访问

使用句柄:
如果使用句柄的话,那么Java堆中将会划分出一块内存来作为句柄池,reference中存储的就是对象的句柄地址,而句柄中包含了对象实例数据与类型数据各自的具体地址信息

直接指针:
如果使用直接指针访问,那么Java堆对象的布局中就必须考虑如何放置访问类型数据的相关信息,而reference中存储的直接就是对象的地址。

什么是安全点

-分析过程中对象引用关系不会发生变化的点
-产品Safepoint的地方:方法调用;循环跳转;异常跳转;
-安全点数量得中

编译型和解释性

编译型:使用专门的编译器,针对特定的平台,将高级语言源代码一次性的编译成可被该平台硬件执行的机器码,并包装成该      平台所能识别的可执行性程序的格式(C、C++、GoLang)
解释性:使用专门的解释器对源程序逐行解释成特定平台的机器码并立即执行。是代码在执行时才被解释器一行行动态翻译       和执行,而不是在执行之前就完成翻译
Java属于编译型+解释型的高级语言

什么时候垃圾回收

1.当Eden区或者S区不够用了
2.老年代空间不够用了
3.方法区空间不够用了
4.System.gc()

实例化一个对象的过程

1.分配内存空间
2.初始化对象
3.将内存空间的地址赋值给对应的引用

大端存储和小端存储

小端存储:便于数据之间的类型转换,例如:long类型转换为int类型时,高地址部分的数据可以直接截掉。
大端存储:便于数据类型的符号判断,因为最低地址位数据即为符号位,可以直接判断数据的正负号

验证java是大端还是小端

loadClass和forName的区别

-使用loadClass()方法获得的Class对象只完成了类加载过程中的第一步:加载,后续的操作均未进行
-使用Class.forName()方法获得Class对象是已经执行完初始化的了

-Xms和-Xmx为什么设置一样

内存空间扩容时会发生内存抖动,影响程序的稳定性,不一样的时候会频繁的触发GC(为了避免在生产环境由于heap内存扩大或缩小导致应用停顿,降低延迟,同时避免每次垃圾回收完成后JVM重新内存分配。所以,-Xmx和-Xms一般都是设置相等的)

tomcat怎么设置jvm参数

添加JVM参数到Tomcat的bin目录下,打开文件catalina.bat,添加如下参数然后保存。set'JAVA_OPTS'

调优参数

-Xms2g:初始化推大小为2g;
-Xmx2g:堆最大内存为2g;
-Xss:规定了每个线程虚拟机栈(堆栈)的大小
-XX:NewRatio=4:设置年轻代和老年代的内存比例为 1:4;
-XX:SurvivorRatio=8:设置新生代Eden和Survivor比例为8:2;
–XX:+UseParNewGC:指定使用 ParNew + Serial Old 垃圾回收器组合;
-XX:+UseParallelOldGC:指定使用ParNew + ParNew Old垃圾回收器组合;
-XX:+UseConcMarkSweepGC:指定使用 CMS + Serial Old 垃圾回收器组合;
-Xmn:新生代的初始大小(-XX:NewSize)
-XX:PermSize:永久代的初始大小
-XX:MaxPermSize:永久代的最大大小
-XX:+PrintGC:开启打印gc信息;
-XX:+PrintGCDetails:打印gc详细信息

各版本垃圾收集器

-jdk1.7默认垃圾收集器Parallel Scavenge(新生代)+Parallel Old(老年代)
-jdk1.8默认(-XX:UseParallelGC)垃圾收集器Parallel Scavenge(新生代)+Parallel Old(老年代)
-JDK1.9默认采用的就是G1垃圾回收器
JDK1.8新特性:
速度更快 – 红黑树
代码更少 – Lambda
强大的Stream API – Stream
便于并行 – Parallel
最大化减少空指针异常 – Optional

JVM性能调优与底层原理分析(学习笔记)

https://blog.csdn.net/xiaowanzi_zj/article/details/120837263

JVM内存模型

https://blog.csdn.net/xiaowanzi_zj/article/details/116105758

判断垃圾以及回收垃圾和四大引用

https://blog.csdn.net/xiaowanzi_zj/article/details/116110943

四种垃圾收集算法和垃圾收集器记忆技巧

https://blog.csdn.net/xiaowanzi_zj/article/details/116111882

深入理解JVM-ZGC垃圾收集器

https://blog.csdn.net/xiaowanzi_zj/article/details/116905022

full gc过于频繁该怎么解决

https://blog.csdn.net/xiaowanzi_zj/article/details/117447235

怎么合理设置JVM内存分配的比例

https://blog.csdn.net/xiaowanzi_zj/article/details/121506749

CMS与三色标记算法

https://blog.csdn.net/xiaowanzi_zj/article/details/121738422

使用JProfiler分析dump文件定位OOM

https://blog.csdn.net/xiaowanzi_zj/article/details/122335429

使用JVisualVM分析dump文件定位OOM

https://blog.csdn.net/xiaowanzi_zj/article/details/122592982

JVM常用命令汇总

https://blog.csdn.net/xiaowanzi_zj/article/details/122422764

JVM的GC日志分析

https://blog.csdn.net/xiaowanzi_zj/article/details/122998876

java获取jvm是32位或64位

第一种:System.getProperty("sun.arch.data.model")
第二种:控制台 java -version
第三种:控制台 java -d32 -version/java -d64 -version

System.gc()和Runtime.getRuntime().gc()区别

https://blog.csdn.net/xiaowanzi_zj/article/details/123910758

jvm核心技术梳理(持续更新)相关推荐

  1. Java虚拟机详解(五)------JVM参数(持续更新)

    JVM参数有很多,其实我们直接使用默认的JVM参数,不去修改都可以满足大多数情况.但是如果你想在有限的硬件资源下,部署的系统达到最大的运行效率,那么进行相关的JVM参数设置是必不可少的.下面我们就来对 ...

  2. [GCN] 图卷积知识梳理 -持续更新

    图卷积知识梳理 文章目录 图卷积知识梳理 1. 为什么 Graph Laplacian L=D−AL=D-AL=D−A --差分的方式理解 2. 为什么是 Graph Laplacian LLL -- ...

  3. 三星以核心技术优势持续更新折叠手机,华为缺乏自主技术无力应对

    媒体报道指三星将在8月份发布galaxy fold2,进一步升级折叠屏技术,这已是它第三代折叠手机.相比之下,此前已连续发布两代折叠手机的华为在折叠屏技术上却未见到新的升级,而只能强调自己在5G芯片技 ...

  4. iOS面试问题全面梳理 --持续更新

    序言 目前,参加到iOS队伍的人是越来越多,形势不容乐观.为iOS应聘者梳理一下面试题,希望能助一臂之力! OC的理解与特性 OC作为一门面向对象的语言,自然具有面向对象的语言特性:封装.继承.多态. ...

  5. 『不再迷茫 - 正则表达式』JS正则要点梳理 持续更新

    [TOC] 写在前面 - Lionad 正在看VueJS的源码, 看到了HtmlParser部分, 感觉以前看的正则表达式基础知识已经完全不够用了, 现翻阅博客资料, 将一些JS中正则表达式难用的部分 ...

  6. Effective C++边读边记主要内容梳理持续更新中...

    Effective C++ 前言 第一章:让自己习惯C++ 条款01:视C++为一个语言联邦 总结: 条款02:尽量以const,enum,inline替换#define 总结: 条款03:尽可能使用 ...

  7. 2、线程池篇 - 从理论基础到具体代码示例讲解(持续更新中......)

    前言 暂无. 一.线程篇 有关线程部分的知识整理请看我下面这篇博客: 1.线程篇 - 从理论到具体代码案例最全线程知识点梳理(持续更新中-) 二.线程池基础知识 线程池优点 他的主要特点为: 线程复用 ...

  8. JVM面试题(史上最强、持续更新、吐血推荐)

    JVM面试题(史上最强.持续更新.吐血推荐) 文章很长,建议收藏起来慢慢读!疯狂创客圈总目录 语雀版 | 总目录 码云版| 总目录 博客园版 为您奉上珍贵的学习资源 : <尼恩Java面试宝典& ...

  9. Linux简单知识点梳理(持续更新中)_莫韵乐的Linux王国

    Linux简单知识点梳理(持续更新中) Linux系统特点 特点 开放性 多用户 良好的用户界面 提供丰富的网络功能 设备独立性 可靠的系统安全 良好的可移植性 ##### Linux系统体系结构 名 ...

  10. 自动驾驶涉及的核心技术与能力(持续更新中)

    以下内容为本人在工作和学习过程中的感悟记录,持续更新中..... 一.语言层面: C++: 1.C 2.类 3.STL 4.模板 5.设计模式 6.数据结构与算法 Python: 二.算法层面: 规划 ...

最新文章

  1. HTML5 服务器发送事件(Server-Sent Events)介绍
  2. sqlserver 两表联查去重_去山东省(烟台)必吃“特色”小吃 ,舌尖5大美食享受!...
  3. 教你如何在面试中用「10分钟快速分析」一款产品
  4. Hi Azure. 从零开始打造一个语音机器人,跟你的电脑聊聊天。
  5. 写csv文件_机器学习Python实践——数据导入(CSV)
  6. 20220213-CTF MISC-a_good_idea(stegsolve工具的使用)-2017_Dating_in_Singapore
  7. python的自带数据集_盘点 | Python自带的那些数据集
  8. 手机可用熵_时间之矢,生命之熵
  9. 2022-03-21 转载办公室之常用职位(英汉)
  10. 10款常用的Linux音乐播放器,10款常用的Linux音乐播放器
  11. IIS管理器无法打开。启动后,在任务栏中有,但是窗口不见了
  12. 百度apollo自动驾驶modules\planning\tasks\optimizers\path_time_heuristic\PathTimeHeuristicOptimizer类代码详解
  13. win8.1兼容matlab吗,Win8.1 安装 Matlab2012a
  14. 补充设定 timer1 定时器和 timer2 定时器定时做多件事
  15. 黑客与技术提示:电脑出现文中现象说明你已经被黑客入侵
  16. python 图像快速替换某种颜色
  17. 右键快捷创建mk文件
  18. 最新《PHP全套学习课程》
  19. 学习指针后对int main(int argc, char *argv[]),“()“内部参数的详解(初学者不要怕,浅浅学过指针的就可以看懂)
  20. ip_forward参数对Linux内核转发影响分析

热门文章

  1. 台式计算机怎么换内存条,笔者教你如何更换电脑内存条
  2. python 取名字_个人儿子叫派森,用python程序化取名字,他管这叫爹?
  3. 王春亮推拿学堂:如何成为一名高级调理师
  4. Grouping BP has not been assigned to any customer accounts groupMessage no. FSBP_ECC004
  5. 顶级域名 一级域名 二级域名 三级域名什么区别?
  6. 阻止软件连接网络(Win)
  7. matlab的数字图像处理,基于MATLAB的数字图像处理分析及应用.pdf
  8. 巴旦木和杏仁的营养价值哪个好?丨巴旦木功效与作用
  9. 计算机c盘小对计算机的影响吗,电脑卡真的跟C盘容量有关系吗?
  10. 生成doc和docx教程